restore include paths for cross-platform builds because i messed absolutely every #include up. dont worry that everything is modified, all i did was normalize line endings because CLRF snuck into the repo and this prevents fake diffs

This commit is contained in:
2026-03-24 19:07:55 -04:00
parent 7d485fdcd7
commit bfecad40be
1340 changed files with 264990 additions and 264996 deletions

View File

@@ -1,404 +1,404 @@
cmake_minimum_required(VERSION 3.21) cmake_minimum_required(VERSION 3.21)
project(MinecraftPE) project(MinecraftPE)
include(cmake/CPM.cmake) include(cmake/CPM.cmake)
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_POLICY_VERSION_MINIMUM 3.10) set(CMAKE_POLICY_VERSION_MINIMUM 3.10)
include(cmake/EnumOption.cmake) include(cmake/EnumOption.cmake)
if(EMSCRIPTEN) if(EMSCRIPTEN)
# When configuring web builds with "emcmake cmake -B build -S .", set PLATFORM to Web by default # When configuring web builds with "emcmake cmake -B build -S .", set PLATFORM to Web by default
set(PLATFORM Web CACHE STRING "Platform to build for.") set(PLATFORM Web CACHE STRING "Platform to build for.")
endif() endif()
enum_option(PLATFORM "Desktop;Web" "Platform to build for.") enum_option(PLATFORM "Desktop;Web" "Platform to build for.")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(OpenSSL) find_package(OpenSSL)
if (${PLATFORM} STREQUAL "Desktop") if (${PLATFORM} STREQUAL "Desktop")
set(PLATFORM_CPP "PLATFORM_DESKTOP") set(PLATFORM_CPP "PLATFORM_DESKTOP")
if (MINGW) if (MINGW)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
endif() endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++11-narrowing -Wno-narrowing -Wno-invalid-source-encoding -Wno-reserved-user-defined-literal") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++11-narrowing -Wno-narrowing -Wno-invalid-source-encoding -Wno-reserved-user-defined-literal")
endif() endif()
if (WIN32) if (WIN32)
add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_CRT_SECURE_NO_WARNINGS)
include_directories(misc/windows) include_directories(misc/windows)
set(EXTRA_LIBS ws2_32 winhttp) set(EXTRA_LIBS ws2_32 winhttp)
elseif(UNIX) elseif(UNIX)
find_library(pthread NAMES pthread) find_library(pthread NAMES pthread)
set(EXTRA_LIBS pthread m) set(EXTRA_LIBS pthread m)
endif() endif()
elseif (${PLATFORM} STREQUAL "Web") elseif (${PLATFORM} STREQUAL "Web")
set(PLATFORM_CPP "PLATFORM_WEB") set(PLATFORM_CPP "PLATFORM_WEB")
set(EXTRA_LIBS "idbfs.js") set(EXTRA_LIBS "idbfs.js")
endif() endif()
# I totally shocked # I totally shocked
if(${PLATFORM} MATCHES "Web") if(${PLATFORM} MATCHES "Web")
set(PNG_LIB png) set(PNG_LIB png)
set(AL_LIBTYPE "STATIC") set(AL_LIBTYPE "STATIC")
add_library(zlib INTERFACE IMPORTED) add_library(zlib INTERFACE IMPORTED)
set_target_properties(zlib PROPERTIES set_target_properties(zlib PROPERTIES
INTERFACE_LINK_OPTIONS "-sUSE_ZLIB=1" INTERFACE_LINK_OPTIONS "-sUSE_ZLIB=1"
) )
add_library(png INTERFACE IMPORTED) add_library(png INTERFACE IMPORTED)
set_target_properties(png PROPERTIES set_target_properties(png PROPERTIES
INTERFACE_COMPILE_OPTIONS "-sUSE_LIBPNG=1" INTERFACE_COMPILE_OPTIONS "-sUSE_LIBPNG=1"
INTERFACE_LINK_OPTIONS "-sUSE_LIBPNG=1" INTERFACE_LINK_OPTIONS "-sUSE_LIBPNG=1"
) )
add_library(glfw INTERFACE IMPORTED) add_library(glfw INTERFACE IMPORTED)
set_target_properties(glfw PROPERTIES set_target_properties(glfw PROPERTIES
INTERFACE_LINK_OPTIONS "-sUSE_GLFW=3" INTERFACE_LINK_OPTIONS "-sUSE_GLFW=3"
) )
else() else()
set(PNG_LIB png_shared) set(PNG_LIB png_shared)
set(AL_LIBTYPE "SHARED") set(AL_LIBTYPE "SHARED")
CPMAddPackage( CPMAddPackage(
NAME "zlib" NAME "zlib"
GIT_REPOSITORY "https://github.com/madler/zlib" GIT_REPOSITORY "https://github.com/madler/zlib"
GIT_TAG "v1.3.2" GIT_TAG "v1.3.2"
) )
CPMAddPackage( CPMAddPackage(
NAME "libpng" NAME "libpng"
GIT_REPOSITORY "https://github.com/pnggroup/libpng.git" GIT_REPOSITORY "https://github.com/pnggroup/libpng.git"
GIT_TAG "v1.6.55" GIT_TAG "v1.6.55"
OPTIONS OPTIONS
"ZLIB_ROOT ${zlib_SOURCE_DIR}" "ZLIB_ROOT ${zlib_SOURCE_DIR}"
"ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR}" "ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR}"
"PNG_TOOLS OFF" "PNG_TOOLS OFF"
"PNG_TESTS OFF" "PNG_TESTS OFF"
) )
CPMAddPackage( CPMAddPackage(
NAME "glfw" NAME "glfw"
GIT_REPOSITORY "https://github.com/glfw/glfw.git" GIT_REPOSITORY "https://github.com/glfw/glfw.git"
GIT_TAG "3.4" GIT_TAG "3.4"
EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_ALL TRUE
OPTIONS OPTIONS
"GLFW_BUILD_EXAMPLES OFF" "GLFW_BUILD_EXAMPLES OFF"
"GLFW_BUILD_TESTS OFF" "GLFW_BUILD_TESTS OFF"
"GLFW_BUILD_DOCS OFF" "GLFW_BUILD_DOCS OFF"
) )
endif() endif()
CPMAddPackage( CPMAddPackage(
NAME "openal" NAME "openal"
GIT_REPOSITORY "https://github.com/kcat/openal-soft.git" GIT_REPOSITORY "https://github.com/kcat/openal-soft.git"
GIT_TAG "1.25.1" GIT_TAG "1.25.1"
OPTIONS OPTIONS
"ALSOFT_EXAMPLES OFF" "ALSOFT_EXAMPLES OFF"
"ALSOFT_TESTS OFF" "ALSOFT_TESTS OFF"
"ALSOFT_UTILS OFF" "ALSOFT_UTILS OFF"
"LIBTYPE ${AL_LIBTYPE}" "LIBTYPE ${AL_LIBTYPE}"
"ALSOFT_ENABLE_MODULES OFF" "ALSOFT_ENABLE_MODULES OFF"
"ALSOFT_STATIC_STDCXX ON" "ALSOFT_STATIC_STDCXX ON"
"ALSOFT_STATIC_LIBGCC ON" "ALSOFT_STATIC_LIBGCC ON"
) )
# TODO: Clear this paths with * # TODO: Clear this paths with *
file(GLOB SERVER_SOURCES file(GLOB SERVER_SOURCES
"project/lib_projects/raknet/jni/RaknetSources/*.cpp" "project/lib_projects/raknet/jni/RaknetSources/*.cpp"
"src/NinecraftApp.cpp" "src/NinecraftApp.cpp"
"src/Performance.cpp" "src/Performance.cpp"
"src/SharedConstants.cpp" "src/SharedConstants.cpp"
"src/client/IConfigListener.cpp" "src/client/IConfigListener.cpp"
"src/client/Minecraft.cpp" "src/client/Minecraft.cpp"
"src/client/OptionStrings.cpp" "src/client/OptionStrings.cpp"
"src/client/Option.cpp" "src/client/Option.cpp"
"src/client/Options.cpp" "src/client/Options.cpp"
"src/client/OptionsFile.cpp" "src/client/OptionsFile.cpp"
"src/client/ServerProfiler.cpp" "src/client/ServerProfiler.cpp"
"src/client/gamemode/CreativeMode.cpp" "src/client/gamemode/CreativeMode.cpp"
"src/client/gamemode/GameMode.cpp" "src/client/gamemode/GameMode.cpp"
"src/client/gamemode/SurvivalMode.cpp" "src/client/gamemode/SurvivalMode.cpp"
"src/client/player/LocalPlayer.cpp" "src/client/player/LocalPlayer.cpp"
"src/client/player/RemotePlayer.cpp" "src/client/player/RemotePlayer.cpp"
"src/client/player/input/KeyboardInput.cpp" "src/client/player/input/KeyboardInput.cpp"
"src/locale/I18n.cpp" "src/locale/I18n.cpp"
"src/main.cpp" "src/main.cpp"
"src/main_dedicated.cpp" "src/main_dedicated.cpp"
"src/nbt/Tag.cpp" "src/nbt/Tag.cpp"
"src/network/ClientSideNetworkHandler.cpp" "src/network/ClientSideNetworkHandler.cpp"
"src/network/NetEventCallback.cpp" "src/network/NetEventCallback.cpp"
"src/network/Packet.cpp" "src/network/Packet.cpp"
"src/network/RakNetInstance.cpp" "src/network/RakNetInstance.cpp"
"src/network/ServerSideNetworkHandler.cpp" "src/network/ServerSideNetworkHandler.cpp"
"src/network/command/CommandServer.cpp" "src/network/command/CommandServer.cpp"
"src/platform/CThread.cpp" "src/platform/CThread.cpp"
"src/platform/HttpClient.cpp" "src/platform/HttpClient.cpp"
"src/platform/PngLoader.cpp" "src/platform/PngLoader.cpp"
"src/platform/time.cpp" "src/platform/time.cpp"
"src/platform/input/Controller.cpp" "src/platform/input/Controller.cpp"
"src/platform/input/Keyboard.cpp" "src/platform/input/Keyboard.cpp"
"src/platform/input/Mouse.cpp" "src/platform/input/Mouse.cpp"
"src/platform/input/Multitouch.cpp" "src/platform/input/Multitouch.cpp"
"src/server/ArgumentsSettings.cpp" "src/server/ArgumentsSettings.cpp"
"src/server/ServerLevel.cpp" "src/server/ServerLevel.cpp"
"src/server/ServerPlayer.cpp" "src/server/ServerPlayer.cpp"
"src/util/DataIO.cpp" "src/util/DataIO.cpp"
"src/util/Mth.cpp" "src/util/Mth.cpp"
"src/util/PerfTimer.cpp" "src/util/PerfTimer.cpp"
"src/util/StringUtils.cpp" "src/util/StringUtils.cpp"
"src/world/Direction.cpp" "src/world/Direction.cpp"
"src/world/entity/*.cpp" "src/world/entity/*.cpp"
"src/world/entity/ai/control/MoveControl.cpp" "src/world/entity/ai/control/MoveControl.cpp"
"src/world/entity/animal/*.cpp" "src/world/entity/animal/*.cpp"
"src/world/entity/item/*.cpp" "src/world/entity/item/*.cpp"
"src/world/entity/monster/*.cpp" "src/world/entity/monster/*.cpp"
"src/world/entity/player/Inventory.cpp" "src/world/entity/player/Inventory.cpp"
"src/world/entity/player/Player.cpp" "src/world/entity/player/Player.cpp"
"src/world/entity/projectile/Arrow.cpp" "src/world/entity/projectile/Arrow.cpp"
"src/world/entity/projectile/Throwable.cpp" "src/world/entity/projectile/Throwable.cpp"
"src/world/food/SimpleFoodData.cpp" "src/world/food/SimpleFoodData.cpp"
"src/world/inventory/*.cpp" "src/world/inventory/*.cpp"
"src/world/item/*.cpp" "src/world/item/*.cpp"
"src/world/item/crafting/*.cpp" "src/world/item/crafting/*.cpp"
"src/world/level/*.cpp" "src/world/level/*.cpp"
"src/world/level/biome/Biome.cpp" "src/world/level/biome/Biome.cpp"
"src/world/level/biome/BiomeSource.cpp" "src/world/level/biome/BiomeSource.cpp"
"src/world/level/chunk/LevelChunk.cpp" "src/world/level/chunk/LevelChunk.cpp"
"src/world/level/dimension/Dimension.cpp" "src/world/level/dimension/Dimension.cpp"
"src/world/level/levelgen/*.cpp" "src/world/level/levelgen/*.cpp"
"src/world/level/levelgen/feature/Feature.cpp" "src/world/level/levelgen/feature/Feature.cpp"
"src/world/level/levelgen/synth/*.cpp" "src/world/level/levelgen/synth/*.cpp"
"src/world/level/material/Material.cpp" "src/world/level/material/Material.cpp"
"src/world/level/pathfinder/Path.cpp" "src/world/level/pathfinder/Path.cpp"
"src/world/level/storage/*.cpp" "src/world/level/storage/*.cpp"
"src/world/level/tile/*.cpp" "src/world/level/tile/*.cpp"
"src/world/level/tile/entity/*.cpp" "src/world/level/tile/entity/*.cpp"
"src/world/phys/HitResult.cpp" "src/world/phys/HitResult.cpp"
) )
file(GLOB CLIENT_SOURCES file(GLOB CLIENT_SOURCES
"src/client/*.cpp" "src/client/*.cpp"
"src/client/gamemode/*.cpp" "src/client/gamemode/*.cpp"
"src/client/gui/*.cpp" "src/client/gui/*.cpp"
"src/client/gui/components/*.cpp" "src/client/gui/components/*.cpp"
"src/client/gui/screens/*.cpp" "src/client/gui/screens/*.cpp"
"src/client/gui/screens/crafting/*.cpp" "src/client/gui/screens/crafting/*.cpp"
"src/client/gui/screens/touch/*.cpp" "src/client/gui/screens/touch/*.cpp"
"src/client/model/*.cpp" "src/client/model/*.cpp"
"src/client/model/geom/*.cpp" "src/client/model/geom/*.cpp"
"src/client/particle/*.cpp" "src/client/particle/*.cpp"
"src/client/player/*.cpp" "src/client/player/*.cpp"
"src/client/player/input/*.cpp" "src/client/player/input/*.cpp"
"src/client/player/input/touchscreen/*.cpp" "src/client/player/input/touchscreen/*.cpp"
"src/client/renderer/*.cpp" "src/client/renderer/*.cpp"
"src/client/renderer/culling/*.cpp" "src/client/renderer/culling/*.cpp"
"src/client/renderer/entity/*.cpp" "src/client/renderer/entity/*.cpp"
"src/client/renderer/ptexture/*.cpp" "src/client/renderer/ptexture/*.cpp"
"src/client/renderer/tileentity/*.cpp" "src/client/renderer/tileentity/*.cpp"
"src/client/sound/*.cpp" "src/client/sound/*.cpp"
"src/locale/*.cpp" "src/locale/*.cpp"
"src/nbt/*.cpp" "src/nbt/*.cpp"
"src/network/*.cpp" "src/network/*.cpp"
"src/network/command/*.cpp" "src/network/command/*.cpp"
"src/platform/*.cpp" "src/platform/*.cpp"
"src/platform/audio/SoundSystemAL.cpp" "src/platform/audio/SoundSystemAL.cpp"
"src/platform/input/*.cpp" "src/platform/input/*.cpp"
"src/raknet/**.cpp" "src/raknet/**.cpp"
"src/server/**.cpp" "src/server/**.cpp"
"src/util/**.cpp" "src/util/**.cpp"
"src/world/*.cpp" "src/world/*.cpp"
"src/world/phys/*.cpp" "src/world/phys/*.cpp"
"src/world/entity/*.cpp" "src/world/entity/*.cpp"
"src/world/entity/ai/control/*.cpp" "src/world/entity/ai/control/*.cpp"
"src/world/entity/animal/*.cpp" "src/world/entity/animal/*.cpp"
"src/world/entity/item/*.cpp" "src/world/entity/item/*.cpp"
"src/world/entity/monster/*.cpp" "src/world/entity/monster/*.cpp"
"src/world/entity/player/*.cpp" "src/world/entity/player/*.cpp"
"src/world/entity/projectile/*.cpp" "src/world/entity/projectile/*.cpp"
"src/world/food/*.cpp" "src/world/food/*.cpp"
"src/world/inventory/*.cpp" "src/world/inventory/*.cpp"
"src/world/item/*.cpp" "src/world/item/*.cpp"
"src/world/item/crafting/*.cpp" "src/world/item/crafting/*.cpp"
"src/world/level/*.cpp" "src/world/level/*.cpp"
"src/world/level/biome/*.cpp" "src/world/level/biome/*.cpp"
"src/world/level/chunk/*.cpp" "src/world/level/chunk/*.cpp"
"src/world/level/dimension/*.cpp" "src/world/level/dimension/*.cpp"
"src/world/level/levelgen/*.cpp" "src/world/level/levelgen/*.cpp"
"src/world/level/levelgen/feature/*.cpp" "src/world/level/levelgen/feature/*.cpp"
"src/world/level/levelgen/synth/*.cpp" "src/world/level/levelgen/synth/*.cpp"
"src/world/level/material/*.cpp" "src/world/level/material/*.cpp"
"src/world/level/pathfinder/*.cpp" "src/world/level/pathfinder/*.cpp"
"src/world/level/storage/*.cpp" "src/world/level/storage/*.cpp"
"src/world/level/tile/*.cpp" "src/world/level/tile/*.cpp"
"src/world/level/tile/entity/*.cpp" "src/world/level/tile/entity/*.cpp"
"src/SharedConstants.cpp" "src/SharedConstants.cpp"
"src/main.cpp" "src/main.cpp"
"src/NinecraftApp.cpp" "src/NinecraftApp.cpp"
"src/AppPlatform_glfw.cpp" "src/AppPlatform_glfw.cpp"
"src/main.cpp" "src/main.cpp"
) )
if (${PLATFORM} STREQUAL "Desktop") if (${PLATFORM} STREQUAL "Desktop")
list(APPEND CLIENT_SOURCES glad/src/glad.c) list(APPEND CLIENT_SOURCES glad/src/glad.c)
endif() endif()
# Server # Server
if(UNIX) if(UNIX)
add_executable("${PROJECT_NAME}-server" ${SERVER_SOURCES}) add_executable("${PROJECT_NAME}-server" ${SERVER_SOURCES})
target_compile_definitions("${PROJECT_NAME}-server" PUBLIC "STANDALONE_SERVER" "SERVER_PROFILER") target_compile_definitions("${PROJECT_NAME}-server" PUBLIC "STANDALONE_SERVER" "SERVER_PROFILER")
target_include_directories("${PROJECT_NAME}-server" PUBLIC target_include_directories("${PROJECT_NAME}-server" PUBLIC
"${CMAKE_SOURCE_DIR}/src/" "${CMAKE_SOURCE_DIR}/src/"
"project/lib_projects/raknet/jni/RaknetSources" "project/lib_projects/raknet/jni/RaknetSources"
) )
target_link_libraries("${PROJECT_NAME}-server" ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries("${PROJECT_NAME}-server" ${CMAKE_THREAD_LIBS_INIT})
endif() endif()
add_executable(${PROJECT_NAME} ${CLIENT_SOURCES}) add_executable(${PROJECT_NAME} ${CLIENT_SOURCES})
target_compile_definitions(${PROJECT_NAME} PUBLIC ${PLATFORM_CPP}) target_compile_definitions(${PROJECT_NAME} PUBLIC ${PLATFORM_CPP})
target_include_directories(${PROJECT_NAME} PUBLIC target_include_directories(${PROJECT_NAME} PUBLIC
"${CMAKE_SOURCE_DIR}/glad/include/" "${CMAKE_SOURCE_DIR}/glad/include/"
"${CMAKE_SOURCE_DIR}/src" "${CMAKE_SOURCE_DIR}/src"
"${openal_SOURCE_DIR}/include" "${openal_SOURCE_DIR}/include"
"${glfw_SOURCE_DIR}/include" "${glfw_SOURCE_DIR}/include"
"lib/include" "lib/include"
) )
if(${PLATFORM} MATCHES "Web") if(${PLATFORM} MATCHES "Web")
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
# uuuh i hate it # uuuh i hate it
set(EM_FLAGS "-pthread -sUSE_PTHREADS=1 -sUSE_LIBPNG=1 -sSHARED_MEMORY=1") set(EM_FLAGS "-pthread -sUSE_PTHREADS=1 -sUSE_LIBPNG=1 -sSHARED_MEMORY=1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EM_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EM_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EM_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EM_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EM_FLAGS} --preload-file ${CMAKE_SOURCE_DIR}/data@/data") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${EM_FLAGS} --preload-file ${CMAKE_SOURCE_DIR}/data@/data")
target_compile_options(${PROJECT_NAME} PUBLIC target_compile_options(${PROJECT_NAME} PUBLIC
"-Os" "-Os"
"-Wno-invalid-source-encoding" "-Wno-invalid-source-encoding"
"-Wno-narrowing" "-Wno-narrowing"
"-Wno-deprecated-register" "-Wno-deprecated-register"
"-Wno-reserved-user-defined-literal" "-Wno-reserved-user-defined-literal"
) )
target_link_options(${PROJECT_NAME} PUBLIC target_link_options(${PROJECT_NAME} PUBLIC
"-Os" "-Os"
"-sALLOW_MEMORY_GROWTH=1" "-sALLOW_MEMORY_GROWTH=1"
"-sFORCE_FILESYSTEM=1" "-sFORCE_FILESYSTEM=1"
"-sLEGACY_GL_EMULATION=1" "-sLEGACY_GL_EMULATION=1"
"-sGL_UNSAFE_OPTS=0" "-sGL_UNSAFE_OPTS=0"
"-sEMULATE_FUNCTION_POINTER_CASTS=1" "-sEMULATE_FUNCTION_POINTER_CASTS=1"
"-sALLOW_TABLE_GROWTH=1" "-sALLOW_TABLE_GROWTH=1"
"-sEXPORTED_RUNTIME_METHODS=['FS','stringToUTF8','UTF8ToString','cwrap','ccall','HEAP8','HEAPU8','HEAP32','HEAPU32']" "-sEXPORTED_RUNTIME_METHODS=['FS','stringToUTF8','UTF8ToString','cwrap','ccall','HEAP8','HEAPU8','HEAP32','HEAPU32']"
"-sEXPORTED_FUNCTIONS=['_main']" "-sEXPORTED_FUNCTIONS=['_main']"
) )
if (CMAKE_BUILD_TYPE STREQUAL "Debug") if (CMAKE_BUILD_TYPE STREQUAL "Debug")
message("DEBUG MODE") message("DEBUG MODE")
target_link_options(${PROJECT_NAME} PUBLIC target_link_options(${PROJECT_NAME} PUBLIC
"-sASSERTIONS=2" "-sASSERTIONS=2"
"-sSTACK_OVERFLOW_CHECK=2" "-sSTACK_OVERFLOW_CHECK=2"
"-sSTACK_SIZE=5242880" "-sSTACK_SIZE=5242880"
"-sGL_DEBUG=1" "-sGL_DEBUG=1"
) )
endif() endif()
target_compile_definitions(${PROJECT_NAME} PUBLIC "__EMSCRIPTEN__" "NO_SOUND" "NO_NETWORK") target_compile_definitions(${PROJECT_NAME} PUBLIC "__EMSCRIPTEN__" "NO_SOUND" "NO_NETWORK")
endif() endif()
# Client # Client
target_compile_definitions(${PROJECT_NAME} PUBLIC "OPENGL_ES" "NO_EGL" ${PLATFORM}) target_compile_definitions(${PROJECT_NAME} PUBLIC "OPENGL_ES" "NO_EGL" ${PLATFORM})
target_link_libraries(${PROJECT_NAME} zlib ${PNG_LIB} OpenAL::OpenAL glfw ${EXTRA_LIBS}) target_link_libraries(${PROJECT_NAME} zlib ${PNG_LIB} OpenAL::OpenAL glfw ${EXTRA_LIBS})
if (OpenSSL_FOUND) if (OpenSSL_FOUND)
target_link_libraries(${PROJECT_NAME} OpenSSL::SSL OpenSSL::Crypto) target_link_libraries(${PROJECT_NAME} OpenSSL::SSL OpenSSL::Crypto)
target_compile_definitions(${PROJECT_NAME} PUBLIC HTTPCLIENT_USE_OPENSSL) target_compile_definitions(${PROJECT_NAME} PUBLIC HTTPCLIENT_USE_OPENSSL)
endif() endif()
if (NOT UNIX) if (NOT UNIX)
add_custom_command( add_custom_command(
TARGET ${PROJECT_NAME} TARGET ${PROJECT_NAME}
POST_BUILD POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:${PROJECT_NAME}> $<TARGET_FILE_DIR:${PROJECT_NAME}> COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:${PROJECT_NAME}> $<TARGET_FILE_DIR:${PROJECT_NAME}>
COMMAND_EXPAND_LISTS COMMAND_EXPAND_LISTS
) )
endif() endif()
if(NOT ${PLATFORM} MATCHES "Web") if(NOT ${PLATFORM} MATCHES "Web")
add_custom_command( add_custom_command(
TARGET ${PROJECT_NAME} TARGET ${PROJECT_NAME}
POST_BUILD POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" $<TARGET_FILE_DIR:${PROJECT_NAME}>/data COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" $<TARGET_FILE_DIR:${PROJECT_NAME}>/data
) )
else() else()
add_custom_command( add_custom_command(
TARGET ${PROJECT_NAME} TARGET ${PROJECT_NAME}
POST_BUILD POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/misc/web/index.html" $<TARGET_FILE_DIR:${PROJECT_NAME}> COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/misc/web/index.html" $<TARGET_FILE_DIR:${PROJECT_NAME}>
) )
endif() endif()
message(STATUS "Compiling with the flags:") message(STATUS "Compiling with the flags:")
message(STATUS " PLATFORM=" ${PLATFORM_CPP}) message(STATUS " PLATFORM=" ${PLATFORM_CPP})

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry excluding="com/mojang/minecraftpe/Minecraft_Verizon.java|com/mojang/minecraftpe/stats/|com/mojang/minecraftpe/Receiver.java|com/mojang/minecraftpe/Minecraft_Market.java" kind="src" path="src"/> <classpathentry excluding="com/mojang/minecraftpe/Minecraft_Verizon.java|com/mojang/minecraftpe/stats/|com/mojang/minecraftpe/Receiver.java|com/mojang/minecraftpe/Minecraft_Market.java" kind="src" path="src"/>
<classpathentry kind="src" path="gen"/> <classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="output" path="bin/classes"/> <classpathentry kind="output" path="bin/classes"/>
</classpath> </classpath>

View File

@@ -1,33 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>MinecraftPocketEdition</name> <name>MinecraftPocketEdition</name>
<comment></comment> <comment></comment>
<projects> <projects>
</projects> </projects>
<buildSpec> <buildSpec>
<buildCommand> <buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name> <name>org.eclipse.jdt.core.javabuilder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name> <name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
</buildSpec> </buildSpec>
<natures> <natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature> <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature> <nature>org.eclipse.jdt.core.javanature</nature>
</natures> </natures>
</projectDescription> </projectDescription>

View File

@@ -1,19 +1,19 @@
<!-- Verizon VCAST --> <!-- Verizon VCAST -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.START_BACKGROUND_SERVICE"/> <uses-permission android:name="android.permission.START_BACKGROUND_SERVICE"/>
<uses-permission android:name="com.verizon.vcast.apps.VCAST_APPS_LICENSE_SERVICE"/> <uses-permission android:name="com.verizon.vcast.apps.VCAST_APPS_LICENSE_SERVICE"/>
android:debuggable="true" android:debuggable="true"
<!-- Android MARKET --> <!-- Android MARKET -->
<uses-permission android:name="com.android.vending.CHECK_LICENSE" /> <uses-permission android:name="com.android.vending.CHECK_LICENSE" />
<uses-library android:name="xperiaplaycertified" android:required="false"/> <uses-library android:name="xperiaplaycertified" android:required="false"/>
<receiver android:name="com.mojang.minecraftpe.Receiver" android:exported="true"> <receiver android:name="com.mojang.minecraftpe.Receiver" android:exported="true">
<intent-filter> <intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" /> <action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter> </intent-filter>
</receiver> </receiver>

File diff suppressed because it is too large Load Diff

View File

@@ -1,281 +1,281 @@
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
# Convert Windows backslashes to forward slashes so NDK toolchain doesnt treat them as escapes. # Convert Windows backslashes to forward slashes so NDK toolchain doesnt treat them as escapes.
LOCAL_PATH := $(subst \,/,$(LOCAL_PATH)) LOCAL_PATH := $(subst \,/,$(LOCAL_PATH))
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := minecraftpe LOCAL_MODULE := minecraftpe
LOCAL_SRC_FILES := ../../../src/main.cpp \ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/main_android_java.cpp \ ../../../src/main_android_java.cpp \
../../../src/platform/audio/SoundSystemSL.cpp \ ../../../src/platform/audio/SoundSystemSL.cpp \
../../../src/platform/input/Controller.cpp \ ../../../src/platform/input/Controller.cpp \
../../../src/platform/input/Keyboard.cpp \ ../../../src/platform/input/Keyboard.cpp \
../../../src/platform/input/Mouse.cpp \ ../../../src/platform/input/Mouse.cpp \
../../../src/platform/input/Multitouch.cpp \ ../../../src/platform/input/Multitouch.cpp \
../../../src/platform/time.cpp \ ../../../src/platform/time.cpp \
../../../src/platform/CThread.cpp \ ../../../src/platform/CThread.cpp \
../../../src/platform/HttpClient.cpp \ ../../../src/platform/HttpClient.cpp \
../../../src/NinecraftApp.cpp \ ../../../src/NinecraftApp.cpp \
../../../src/Performance.cpp \ ../../../src/Performance.cpp \
../../../src/SharedConstants.cpp \ ../../../src/SharedConstants.cpp \
../../../src/client/IConfigListener.cpp \ ../../../src/client/IConfigListener.cpp \
../../../src/client/Minecraft.cpp \ ../../../src/client/Minecraft.cpp \
../../../src/client/MouseHandler.cpp \ ../../../src/client/MouseHandler.cpp \
../../../src/client/Options.cpp \ ../../../src/client/Options.cpp \
../../../src/client/OptionsFile.cpp \ ../../../src/client/OptionsFile.cpp \
../../../src/client/OptionStrings.cpp \ ../../../src/client/OptionStrings.cpp \
../../../src/client/Option.cpp \ ../../../src/client/Option.cpp \
../../../src/client/gamemode/GameMode.cpp \ ../../../src/client/gamemode/GameMode.cpp \
../../../src/client/gamemode/CreativeMode.cpp \ ../../../src/client/gamemode/CreativeMode.cpp \
../../../src/client/gamemode/SurvivalMode.cpp \ ../../../src/client/gamemode/SurvivalMode.cpp \
../../../src/client/gui/components/Button.cpp \ ../../../src/client/gui/components/Button.cpp \
../../../src/client/gui/components/GuiElement.cpp \ ../../../src/client/gui/components/GuiElement.cpp \
../../../src/client/gui/components/GuiElementContainer.cpp \ ../../../src/client/gui/components/GuiElementContainer.cpp \
../../../src/client/gui/components/ImageButton.cpp \ ../../../src/client/gui/components/ImageButton.cpp \
../../../src/client/gui/components/ItemPane.cpp \ ../../../src/client/gui/components/ItemPane.cpp \
../../../src/client/gui/components/InventoryPane.cpp \ ../../../src/client/gui/components/InventoryPane.cpp \
../../../src/client/gui/components/LargeImageButton.cpp \ ../../../src/client/gui/components/LargeImageButton.cpp \
../../../src/client/gui/components/NinePatch.cpp \ ../../../src/client/gui/components/NinePatch.cpp \
../../../src/client/gui/components/OptionsGroup.cpp \ ../../../src/client/gui/components/OptionsGroup.cpp \
../../../src/client/gui/components/OptionsItem.cpp \ ../../../src/client/gui/components/OptionsItem.cpp \
../../../src/client/gui/components/KeyOption.cpp \ ../../../src/client/gui/components/KeyOption.cpp \
../../../src/client/gui/components/TextOption.cpp \ ../../../src/client/gui/components/TextOption.cpp \
../../../src/client/gui/components/RolledSelectionListH.cpp \ ../../../src/client/gui/components/RolledSelectionListH.cpp \
../../../src/client/gui/components/RolledSelectionListV.cpp \ ../../../src/client/gui/components/RolledSelectionListV.cpp \
../../../src/client/gui/components/ScrolledSelectionList.cpp \ ../../../src/client/gui/components/ScrolledSelectionList.cpp \
../../../src/client/gui/components/ScrollingPane.cpp \ ../../../src/client/gui/components/ScrollingPane.cpp \
../../../src/client/gui/components/Slider.cpp \ ../../../src/client/gui/components/Slider.cpp \
../../../src/client/gui/components/TextBox.cpp \ ../../../src/client/gui/components/TextBox.cpp \
../../../src/client/gui/Font.cpp \ ../../../src/client/gui/Font.cpp \
../../../src/client/gui/Gui.cpp \ ../../../src/client/gui/Gui.cpp \
../../../src/client/gui/GuiComponent.cpp \ ../../../src/client/gui/GuiComponent.cpp \
../../../src/client/gui/Screen.cpp \ ../../../src/client/gui/Screen.cpp \
../../../src/client/gui/screens/ScreenChooser.cpp \ ../../../src/client/gui/screens/ScreenChooser.cpp \
../../../src/client/gui/screens/ArmorScreen.cpp \ ../../../src/client/gui/screens/ArmorScreen.cpp \
../../../src/client/gui/screens/ChatScreen.cpp \ ../../../src/client/gui/screens/ChatScreen.cpp \
../../../src/client/gui/screens/ChooseLevelScreen.cpp \ ../../../src/client/gui/screens/ChooseLevelScreen.cpp \
../../../src/client/gui/screens/SimpleChooseLevelScreen.cpp \ ../../../src/client/gui/screens/SimpleChooseLevelScreen.cpp \
../../../src/client/gui/screens/ConsoleScreen.cpp \ ../../../src/client/gui/screens/ConsoleScreen.cpp \
../../../src/client/gui/screens/UsernameScreen.cpp \ ../../../src/client/gui/screens/UsernameScreen.cpp \
../../../src/client/gui/screens/ConfirmScreen.cpp \ ../../../src/client/gui/screens/ConfirmScreen.cpp \
../../../src/client/gui/screens/ChestScreen.cpp \ ../../../src/client/gui/screens/ChestScreen.cpp \
../../../src/client/gui/screens/DeathScreen.cpp \ ../../../src/client/gui/screens/DeathScreen.cpp \
../../../src/client/gui/screens/FurnaceScreen.cpp \ ../../../src/client/gui/screens/FurnaceScreen.cpp \
../../../src/client/gui/screens/InBedScreen.cpp \ ../../../src/client/gui/screens/InBedScreen.cpp \
../../../src/client/gui/screens/IngameBlockSelectionScreen.cpp \ ../../../src/client/gui/screens/IngameBlockSelectionScreen.cpp \
../../../src/client/gui/screens/JoinGameScreen.cpp \ ../../../src/client/gui/screens/JoinGameScreen.cpp \
../../../src/client/gui/screens/OptionsScreen.cpp \ ../../../src/client/gui/screens/OptionsScreen.cpp \
../../../src/client/gui/screens/CreditsScreen.cpp \ ../../../src/client/gui/screens/CreditsScreen.cpp \
../../../src/client/gui/screens/PauseScreen.cpp \ ../../../src/client/gui/screens/PauseScreen.cpp \
../../../src/client/gui/screens/ProgressScreen.cpp \ ../../../src/client/gui/screens/ProgressScreen.cpp \
../../../src/client/gui/screens/RenameMPLevelScreen.cpp \ ../../../src/client/gui/screens/RenameMPLevelScreen.cpp \
../../../src/client/gui/screens/SelectWorldScreen.cpp \ ../../../src/client/gui/screens/SelectWorldScreen.cpp \
../../../src/client/gui/screens/StartMenuScreen.cpp \ ../../../src/client/gui/screens/StartMenuScreen.cpp \
../../../src/client/gui/screens/TextEditScreen.cpp \ ../../../src/client/gui/screens/TextEditScreen.cpp \
../../../src/client/gui/screens/JoinByIPScreen.cpp \ ../../../src/client/gui/screens/JoinByIPScreen.cpp \
../../../src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp \ ../../../src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp \
../../../src/client/gui/screens/touch/TouchJoinGameScreen.cpp \ ../../../src/client/gui/screens/touch/TouchJoinGameScreen.cpp \
../../../src/client/gui/screens/touch/TouchSelectWorldScreen.cpp \ ../../../src/client/gui/screens/touch/TouchSelectWorldScreen.cpp \
../../../src/client/gui/screens/touch/TouchStartMenuScreen.cpp \ ../../../src/client/gui/screens/touch/TouchStartMenuScreen.cpp \
../../../src/client/gui/screens/UploadPhotoScreen.cpp \ ../../../src/client/gui/screens/UploadPhotoScreen.cpp \
../../../src/client/gui/screens/crafting/CraftingFilters.cpp \ ../../../src/client/gui/screens/crafting/CraftingFilters.cpp \
../../../src/client/gui/screens/crafting/PaneCraftingScreen.cpp \ ../../../src/client/gui/screens/crafting/PaneCraftingScreen.cpp \
../../../src/client/gui/screens/crafting/StonecutterScreen.cpp \ ../../../src/client/gui/screens/crafting/StonecutterScreen.cpp \
../../../src/client/gui/screens/crafting/WorkbenchScreen.cpp \ ../../../src/client/gui/screens/crafting/WorkbenchScreen.cpp \
../../../src/client/model/ChickenModel.cpp \ ../../../src/client/model/ChickenModel.cpp \
../../../src/client/model/CowModel.cpp \ ../../../src/client/model/CowModel.cpp \
../../../src/client/model/HumanoidModel.cpp \ ../../../src/client/model/HumanoidModel.cpp \
../../../src/client/model/PigModel.cpp \ ../../../src/client/model/PigModel.cpp \
../../../src/client/model/SheepFurModel.cpp \ ../../../src/client/model/SheepFurModel.cpp \
../../../src/client/model/SheepModel.cpp \ ../../../src/client/model/SheepModel.cpp \
../../../src/client/model/QuadrupedModel.cpp \ ../../../src/client/model/QuadrupedModel.cpp \
../../../src/client/model/geom/Cube.cpp \ ../../../src/client/model/geom/Cube.cpp \
../../../src/client/model/geom/ModelPart.cpp \ ../../../src/client/model/geom/ModelPart.cpp \
../../../src/client/model/geom/Polygon.cpp \ ../../../src/client/model/geom/Polygon.cpp \
../../../src/client/particle/Particle.cpp \ ../../../src/client/particle/Particle.cpp \
../../../src/client/particle/ParticleEngine.cpp \ ../../../src/client/particle/ParticleEngine.cpp \
../../../src/client/player/LocalPlayer.cpp \ ../../../src/client/player/LocalPlayer.cpp \
../../../src/client/player/RemotePlayer.cpp \ ../../../src/client/player/RemotePlayer.cpp \
../../../src/client/player/input/KeyboardInput.cpp \ ../../../src/client/player/input/KeyboardInput.cpp \
../../../src/client/player/input/touchscreen/TouchscreenInput.cpp \ ../../../src/client/player/input/touchscreen/TouchscreenInput.cpp \
../../../src/client/renderer/Chunk.cpp \ ../../../src/client/renderer/Chunk.cpp \
../../../src/client/renderer/EntityTileRenderer.cpp \ ../../../src/client/renderer/EntityTileRenderer.cpp \
../../../src/client/renderer/GameRenderer.cpp \ ../../../src/client/renderer/GameRenderer.cpp \
../../../src/client/renderer/ItemInHandRenderer.cpp \ ../../../src/client/renderer/ItemInHandRenderer.cpp \
../../../src/client/renderer/LevelRenderer.cpp \ ../../../src/client/renderer/LevelRenderer.cpp \
../../../src/client/renderer/RenderChunk.cpp \ ../../../src/client/renderer/RenderChunk.cpp \
../../../src/client/renderer/RenderList.cpp \ ../../../src/client/renderer/RenderList.cpp \
../../../src/client/renderer/Tesselator.cpp \ ../../../src/client/renderer/Tesselator.cpp \
../../../src/client/renderer/Textures.cpp \ ../../../src/client/renderer/Textures.cpp \
../../../src/client/renderer/TileRenderer.cpp \ ../../../src/client/renderer/TileRenderer.cpp \
../../../src/client/renderer/gles.cpp \ ../../../src/client/renderer/gles.cpp \
../../../src/client/renderer/culling/Frustum.cpp \ ../../../src/client/renderer/culling/Frustum.cpp \
../../../src/client/renderer/entity/ArrowRenderer.cpp \ ../../../src/client/renderer/entity/ArrowRenderer.cpp \
../../../src/client/renderer/entity/ChickenRenderer.cpp \ ../../../src/client/renderer/entity/ChickenRenderer.cpp \
../../../src/client/renderer/entity/EntityRenderDispatcher.cpp \ ../../../src/client/renderer/entity/EntityRenderDispatcher.cpp \
../../../src/client/renderer/entity/EntityRenderer.cpp \ ../../../src/client/renderer/entity/EntityRenderer.cpp \
../../../src/client/renderer/entity/FallingTileRenderer.cpp \ ../../../src/client/renderer/entity/FallingTileRenderer.cpp \
../../../src/client/renderer/entity/HumanoidMobRenderer.cpp \ ../../../src/client/renderer/entity/HumanoidMobRenderer.cpp \
../../../src/client/renderer/entity/ItemRenderer.cpp \ ../../../src/client/renderer/entity/ItemRenderer.cpp \
../../../src/client/renderer/entity/ItemSpriteRenderer.cpp \ ../../../src/client/renderer/entity/ItemSpriteRenderer.cpp \
../../../src/client/renderer/entity/MobRenderer.cpp \ ../../../src/client/renderer/entity/MobRenderer.cpp \
../../../src/client/renderer/entity/PaintingRenderer.cpp \ ../../../src/client/renderer/entity/PaintingRenderer.cpp \
../../../src/client/renderer/entity/PlayerRenderer.cpp \ ../../../src/client/renderer/entity/PlayerRenderer.cpp \
../../../src/client/renderer/entity/SheepRenderer.cpp \ ../../../src/client/renderer/entity/SheepRenderer.cpp \
../../../src/client/renderer/entity/TntRenderer.cpp \ ../../../src/client/renderer/entity/TntRenderer.cpp \
../../../src/client/renderer/entity/TripodCameraRenderer.cpp \ ../../../src/client/renderer/entity/TripodCameraRenderer.cpp \
../../../src/client/renderer/ptexture/DynamicTexture.cpp \ ../../../src/client/renderer/ptexture/DynamicTexture.cpp \
../../../src/client/renderer/tileentity/ChestRenderer.cpp \ ../../../src/client/renderer/tileentity/ChestRenderer.cpp \
../../../src/client/renderer/tileentity/SignRenderer.cpp \ ../../../src/client/renderer/tileentity/SignRenderer.cpp \
../../../src/client/renderer/tileentity/TileEntityRenderDispatcher.cpp \ ../../../src/client/renderer/tileentity/TileEntityRenderDispatcher.cpp \
../../../src/client/renderer/tileentity/TileEntityRenderer.cpp \ ../../../src/client/renderer/tileentity/TileEntityRenderer.cpp \
../../../src/client/sound/Sound.cpp \ ../../../src/client/sound/Sound.cpp \
../../../src/client/sound/SoundEngine.cpp \ ../../../src/client/sound/SoundEngine.cpp \
../../../src/locale/I18n.cpp \ ../../../src/locale/I18n.cpp \
../../../src/nbt/Tag.cpp \ ../../../src/nbt/Tag.cpp \
../../../src/network/command/CommandServer.cpp \ ../../../src/network/command/CommandServer.cpp \
../../../src/network/ClientSideNetworkHandler.cpp \ ../../../src/network/ClientSideNetworkHandler.cpp \
../../../src/network/NetEventCallback.cpp \ ../../../src/network/NetEventCallback.cpp \
../../../src/network/Packet.cpp \ ../../../src/network/Packet.cpp \
../../../src/network/RakNetInstance.cpp \ ../../../src/network/RakNetInstance.cpp \
../../../src/network/ServerSideNetworkHandler.cpp \ ../../../src/network/ServerSideNetworkHandler.cpp \
../../../src/server/ServerLevel.cpp \ ../../../src/server/ServerLevel.cpp \
../../../src/server/ServerPlayer.cpp \ ../../../src/server/ServerPlayer.cpp \
../../../src/util/DataIO.cpp \ ../../../src/util/DataIO.cpp \
../../../src/util/Mth.cpp \ ../../../src/util/Mth.cpp \
../../../src/util/StringUtils.cpp \ ../../../src/util/StringUtils.cpp \
../../../src/util/PerfTimer.cpp \ ../../../src/util/PerfTimer.cpp \
../../../src/util/PerfRenderer.cpp \ ../../../src/util/PerfRenderer.cpp \
../../../src/world/Direction.cpp \ ../../../src/world/Direction.cpp \
../../../src/world/entity/AgableMob.cpp \ ../../../src/world/entity/AgableMob.cpp \
../../../src/world/entity/Entity.cpp \ ../../../src/world/entity/Entity.cpp \
../../../src/world/entity/EntityFactory.cpp \ ../../../src/world/entity/EntityFactory.cpp \
../../../src/world/entity/FlyingMob.cpp \ ../../../src/world/entity/FlyingMob.cpp \
../../../src/world/entity/HangingEntity.cpp \ ../../../src/world/entity/HangingEntity.cpp \
../../../src/world/entity/Mob.cpp \ ../../../src/world/entity/Mob.cpp \
../../../src/world/entity/MobCategory.cpp \ ../../../src/world/entity/MobCategory.cpp \
../../../src/world/entity/Motive.cpp \ ../../../src/world/entity/Motive.cpp \
../../../src/world/entity/Painting.cpp \ ../../../src/world/entity/Painting.cpp \
../../../src/world/entity/PathfinderMob.cpp \ ../../../src/world/entity/PathfinderMob.cpp \
../../../src/world/entity/SynchedEntityData.cpp \ ../../../src/world/entity/SynchedEntityData.cpp \
../../../src/world/entity/ai/control/MoveControl.cpp \ ../../../src/world/entity/ai/control/MoveControl.cpp \
../../../src/world/entity/animal/Animal.cpp \ ../../../src/world/entity/animal/Animal.cpp \
../../../src/world/entity/animal/Chicken.cpp \ ../../../src/world/entity/animal/Chicken.cpp \
../../../src/world/entity/animal/Cow.cpp \ ../../../src/world/entity/animal/Cow.cpp \
../../../src/world/entity/animal/Pig.cpp \ ../../../src/world/entity/animal/Pig.cpp \
../../../src/world/entity/animal/Sheep.cpp \ ../../../src/world/entity/animal/Sheep.cpp \
../../../src/world/entity/animal/WaterAnimal.cpp \ ../../../src/world/entity/animal/WaterAnimal.cpp \
../../../src/world/entity/item/FallingTile.cpp \ ../../../src/world/entity/item/FallingTile.cpp \
../../../src/world/entity/item/ItemEntity.cpp \ ../../../src/world/entity/item/ItemEntity.cpp \
../../../src/world/entity/item/PrimedTnt.cpp \ ../../../src/world/entity/item/PrimedTnt.cpp \
../../../src/world/entity/item/TripodCamera.cpp \ ../../../src/world/entity/item/TripodCamera.cpp \
../../../src/world/entity/monster/Creeper.cpp \ ../../../src/world/entity/monster/Creeper.cpp \
../../../src/world/entity/monster/Monster.cpp \ ../../../src/world/entity/monster/Monster.cpp \
../../../src/world/entity/monster/PigZombie.cpp \ ../../../src/world/entity/monster/PigZombie.cpp \
../../../src/world/entity/monster/Skeleton.cpp \ ../../../src/world/entity/monster/Skeleton.cpp \
../../../src/world/entity/monster/Spider.cpp \ ../../../src/world/entity/monster/Spider.cpp \
../../../src/world/entity/monster/Zombie.cpp \ ../../../src/world/entity/monster/Zombie.cpp \
../../../src/world/entity/projectile/Arrow.cpp \ ../../../src/world/entity/projectile/Arrow.cpp \
../../../src/world/entity/projectile/Throwable.cpp \ ../../../src/world/entity/projectile/Throwable.cpp \
../../../src/world/entity/player/Inventory.cpp \ ../../../src/world/entity/player/Inventory.cpp \
../../../src/world/entity/player/Player.cpp \ ../../../src/world/entity/player/Player.cpp \
../../../src/world/food/SimpleFoodData.cpp \ ../../../src/world/food/SimpleFoodData.cpp \
../../../src/world/inventory/BaseContainerMenu.cpp \ ../../../src/world/inventory/BaseContainerMenu.cpp \
../../../src/world/inventory/ContainerMenu.cpp \ ../../../src/world/inventory/ContainerMenu.cpp \
../../../src/world/inventory/FillingContainer.cpp \ ../../../src/world/inventory/FillingContainer.cpp \
../../../src/world/inventory/FurnaceMenu.cpp \ ../../../src/world/inventory/FurnaceMenu.cpp \
../../../src/world/item/ArmorItem.cpp \ ../../../src/world/item/ArmorItem.cpp \
../../../src/world/item/BedItem.cpp \ ../../../src/world/item/BedItem.cpp \
../../../src/world/item/DyePowderItem.cpp \ ../../../src/world/item/DyePowderItem.cpp \
../../../src/world/item/Item.cpp \ ../../../src/world/item/Item.cpp \
../../../src/world/item/ItemInstance.cpp \ ../../../src/world/item/ItemInstance.cpp \
../../../src/world/item/HangingEntityItem.cpp \ ../../../src/world/item/HangingEntityItem.cpp \
../../../src/world/item/HatchetItem.cpp \ ../../../src/world/item/HatchetItem.cpp \
../../../src/world/item/HoeItem.cpp \ ../../../src/world/item/HoeItem.cpp \
../../../src/world/item/PickaxeItem.cpp \ ../../../src/world/item/PickaxeItem.cpp \
../../../src/world/item/ShovelItem.cpp \ ../../../src/world/item/ShovelItem.cpp \
../../../src/world/item/crafting/ArmorRecipes.cpp \ ../../../src/world/item/crafting/ArmorRecipes.cpp \
../../../src/world/item/crafting/Recipe.cpp \ ../../../src/world/item/crafting/Recipe.cpp \
../../../src/world/item/crafting/Recipes.cpp \ ../../../src/world/item/crafting/Recipes.cpp \
../../../src/world/item/crafting/FurnaceRecipes.cpp \ ../../../src/world/item/crafting/FurnaceRecipes.cpp \
../../../src/world/item/crafting/OreRecipes.cpp \ ../../../src/world/item/crafting/OreRecipes.cpp \
../../../src/world/item/crafting/StructureRecipes.cpp \ ../../../src/world/item/crafting/StructureRecipes.cpp \
../../../src/world/item/crafting/ToolRecipes.cpp \ ../../../src/world/item/crafting/ToolRecipes.cpp \
../../../src/world/item/crafting/WeaponRecipes.cpp \ ../../../src/world/item/crafting/WeaponRecipes.cpp \
../../../src/world/level/Explosion.cpp \ ../../../src/world/level/Explosion.cpp \
../../../src/world/level/Level.cpp \ ../../../src/world/level/Level.cpp \
../../../src/world/level/LightLayer.cpp \ ../../../src/world/level/LightLayer.cpp \
../../../src/world/level/LightUpdate.cpp \ ../../../src/world/level/LightUpdate.cpp \
../../../src/world/level/MobSpawner.cpp \ ../../../src/world/level/MobSpawner.cpp \
../../../src/world/level/Region.cpp \ ../../../src/world/level/Region.cpp \
../../../src/world/level/TickNextTickData.cpp \ ../../../src/world/level/TickNextTickData.cpp \
../../../src/world/level/biome/Biome.cpp \ ../../../src/world/level/biome/Biome.cpp \
../../../src/world/level/biome/BiomeSource.cpp \ ../../../src/world/level/biome/BiomeSource.cpp \
../../../src/world/level/chunk/LevelChunk.cpp \ ../../../src/world/level/chunk/LevelChunk.cpp \
../../../src/world/level/dimension/Dimension.cpp \ ../../../src/world/level/dimension/Dimension.cpp \
../../../src/world/level/levelgen/CanyonFeature.cpp \ ../../../src/world/level/levelgen/CanyonFeature.cpp \
../../../src/world/level/levelgen/DungeonFeature.cpp \ ../../../src/world/level/levelgen/DungeonFeature.cpp \
../../../src/world/level/levelgen/LargeCaveFeature.cpp \ ../../../src/world/level/levelgen/LargeCaveFeature.cpp \
../../../src/world/level/levelgen/LargeFeature.cpp \ ../../../src/world/level/levelgen/LargeFeature.cpp \
../../../src/world/level/levelgen/RandomLevelSource.cpp \ ../../../src/world/level/levelgen/RandomLevelSource.cpp \
../../../src/world/level/levelgen/feature/Feature.cpp \ ../../../src/world/level/levelgen/feature/Feature.cpp \
../../../src/world/level/levelgen/synth/ImprovedNoise.cpp \ ../../../src/world/level/levelgen/synth/ImprovedNoise.cpp \
../../../src/world/level/levelgen/synth/PerlinNoise.cpp \ ../../../src/world/level/levelgen/synth/PerlinNoise.cpp \
../../../src/world/level/levelgen/synth/Synth.cpp \ ../../../src/world/level/levelgen/synth/Synth.cpp \
../../../src/world/level/material/Material.cpp \ ../../../src/world/level/material/Material.cpp \
../../../src/world/level/pathfinder/Path.cpp \ ../../../src/world/level/pathfinder/Path.cpp \
../../../src/world/level/storage/ExternalFileLevelStorage.cpp \ ../../../src/world/level/storage/ExternalFileLevelStorage.cpp \
../../../src/world/level/storage/ExternalFileLevelStorageSource.cpp \ ../../../src/world/level/storage/ExternalFileLevelStorageSource.cpp \
../../../src/world/level/storage/FolderMethods.cpp \ ../../../src/world/level/storage/FolderMethods.cpp \
../../../src/world/level/storage/LevelData.cpp \ ../../../src/world/level/storage/LevelData.cpp \
../../../src/world/level/storage/LevelStorageSource.cpp \ ../../../src/world/level/storage/LevelStorageSource.cpp \
../../../src/world/level/storage/RegionFile.cpp \ ../../../src/world/level/storage/RegionFile.cpp \
../../../src/world/level/tile/BedTile.cpp \ ../../../src/world/level/tile/BedTile.cpp \
../../../src/world/level/tile/ChestTile.cpp \ ../../../src/world/level/tile/ChestTile.cpp \
../../../src/world/level/tile/CropTile.cpp \ ../../../src/world/level/tile/CropTile.cpp \
../../../src/world/level/tile/DoorTile.cpp \ ../../../src/world/level/tile/DoorTile.cpp \
../../../src/world/level/tile/EntityTile.cpp \ ../../../src/world/level/tile/EntityTile.cpp \
../../../src/world/level/tile/FurnaceTile.cpp \ ../../../src/world/level/tile/FurnaceTile.cpp \
../../../src/world/level/tile/GrassTile.cpp \ ../../../src/world/level/tile/GrassTile.cpp \
../../../src/world/level/tile/HeavyTile.cpp \ ../../../src/world/level/tile/HeavyTile.cpp \
../../../src/world/level/tile/LightGemTile.cpp \ ../../../src/world/level/tile/LightGemTile.cpp \
../../../src/world/level/tile/MelonTile.cpp \ ../../../src/world/level/tile/MelonTile.cpp \
../../../src/world/level/tile/Mushroom.cpp \ ../../../src/world/level/tile/Mushroom.cpp \
../../../src/world/level/tile/NetherReactor.cpp \ ../../../src/world/level/tile/NetherReactor.cpp \
../../../src/world/level/tile/NetherReactorPattern.cpp \ ../../../src/world/level/tile/NetherReactorPattern.cpp \
../../../src/world/level/tile/StairTile.cpp \ ../../../src/world/level/tile/StairTile.cpp \
../../../src/world/level/tile/StemTile.cpp \ ../../../src/world/level/tile/StemTile.cpp \
../../../src/world/level/tile/StoneSlabTile.cpp \ ../../../src/world/level/tile/StoneSlabTile.cpp \
../../../src/world/level/tile/TallGrass.cpp \ ../../../src/world/level/tile/TallGrass.cpp \
../../../src/world/level/tile/Tile.cpp \ ../../../src/world/level/tile/Tile.cpp \
../../../src/world/level/tile/TrapDoorTile.cpp \ ../../../src/world/level/tile/TrapDoorTile.cpp \
../../../src/world/level/tile/entity/ChestTileEntity.cpp \ ../../../src/world/level/tile/entity/ChestTileEntity.cpp \
../../../src/world/level/tile/entity/NetherReactorTileEntity.cpp \ ../../../src/world/level/tile/entity/NetherReactorTileEntity.cpp \
../../../src/world/level/tile/entity/SignTileEntity.cpp \ ../../../src/world/level/tile/entity/SignTileEntity.cpp \
../../../src/world/level/tile/entity/TileEntity.cpp \ ../../../src/world/level/tile/entity/TileEntity.cpp \
../../../src/world/level/tile/entity/FurnaceTileEntity.cpp \ ../../../src/world/level/tile/entity/FurnaceTileEntity.cpp \
../../../src/world/phys/HitResult.cpp ../../../src/world/phys/HitResult.cpp
LOCAL_CFLAGS := -DPLATFORM_ANDROID -DPRE_ANDROID23 -Wno-narrowing $(LOCAL_CFLAGS) LOCAL_CFLAGS := -DPLATFORM_ANDROID -DPRE_ANDROID23 -Wno-narrowing $(LOCAL_CFLAGS)
LOCAL_CPPFLAGS := -std=c++14 -frtti LOCAL_CPPFLAGS := -std=c++14 -frtti
LOCAL_CPPFLAGS += -frtti LOCAL_CPPFLAGS += -frtti
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../src LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../src
#LOCAL_CFLAGS := -DANDROID_PUBLISH -DDEMO_MODE $(LOCAL_CFLAGS) #LOCAL_CFLAGS := -DANDROID_PUBLISH -DDEMO_MODE $(LOCAL_CFLAGS)
#LOCAL_CFLAGS := -DANDROID_PUBLISH $(LOCAL_CFLAGS) #LOCAL_CFLAGS := -DANDROID_PUBLISH $(LOCAL_CFLAGS)
#LOCAL_CFLAGS := -DDEMO_MODE -DGLDEBUG $(LOCAL_CFLAGS) #LOCAL_CFLAGS := -DDEMO_MODE -DGLDEBUG $(LOCAL_CFLAGS)
#LOCAL_CFLAGS := -DGLDEBUG $(LOCAL_CFLAGS) #LOCAL_CFLAGS := -DGLDEBUG $(LOCAL_CFLAGS)
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM -lOpenSLES LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM -lOpenSLES
LOCAL_STATIC_LIBRARIES := android_native_app_glue RakNet LOCAL_STATIC_LIBRARIES := android_native_app_glue RakNet
#LOCAL_CPP_FEATURES := exceptions #LOCAL_CPP_FEATURES := exceptions
TARGET_ARCH_ABI := armeabi-v7a TARGET_ARCH_ABI := armeabi-v7a
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)
# NOTE: environment var NDK_MODULE_PATH needs to point to lib_projects folder # NOTE: environment var NDK_MODULE_PATH needs to point to lib_projects folder
$(call import-module,android/native_app_glue) $(call import-module,android/native_app_glue)
$(call import-module, raknet/jni) $(call import-module, raknet/jni)

View File

@@ -1,68 +1,68 @@
-optimizationpasses 5 -optimizationpasses 5
-dontusemixedcaseclassnames -dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclasses
-dontpreverify -dontpreverify
-printseeds -printseeds
-verbose -verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class com.mojang.minecraftpe.GameModeButton -keep public class com.mojang.minecraftpe.GameModeButton
-keep public class com.mojang.android.StringValue -keep public class com.mojang.android.StringValue
-keep public class * extends android.app.Activity -keep public class * extends android.app.Activity
-keep public class * extends com.mojang.minecraftpe.MainActivity -keep public class * extends com.mojang.minecraftpe.MainActivity
-keep public class * extends MainActivity -keep public class * extends MainActivity
-keep public class * extends android.app.Application -keep public class * extends android.app.Application
-keep public class * extends android.app.Service -keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider -keep public class * extends android.content.ContentProvider
-keep public class com.android.vending.licensing.ILicensingService -keep public class com.android.vending.licensing.ILicensingService
-keep,allowobfuscation class com.mojang.** { *** *(...); } -keep,allowobfuscation class com.mojang.** { *** *(...); }
-keepclasseswithmembernames class * { -keepclasseswithmembernames class * {
native <methods>; native <methods>;
} }
-keepclasseswithmembernames class * { -keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet); public <init>(android.content.Context, android.util.AttributeSet);
} }
-keepclasseswithmembernames class * { -keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int); public <init>(android.content.Context, android.util.AttributeSet, int);
} }
-keepclassmembers enum * { -keepclassmembers enum * {
public static **[] values(); public static **[] values();
public static ** valueOf(java.lang.String); public static ** valueOf(java.lang.String);
} }
-keepclassmembers class * extends android.app.Activity { -keepclassmembers class * extends android.app.Activity {
static public void saveScreenshot(java.lang.String, int, int, int[]); static public void saveScreenshot(java.lang.String, int, int, int[]);
public int[] getImageData(java.lang.String); public int[] getImageData(java.lang.String);
public byte[] getFileDataBytes(java.lang.String); public byte[] getFileDataBytes(java.lang.String);
public java.lang.String getPlatformStringVar(int); public java.lang.String getPlatformStringVar(int);
public int getScreenWidth(); public int getScreenWidth();
public int getScreenHeight(); public int getScreenHeight();
public float getPixelsPerMillimeter(); public float getPixelsPerMillimeter();
public int checkLicense(); public int checkLicense();
public boolean isNetworkEnabled(boolean); public boolean isNetworkEnabled(boolean);
public java.lang.String getDateString(int); public java.lang.String getDateString(int);
public boolean hasBuyButtonWhenInvalidLicense(); public boolean hasBuyButtonWhenInvalidLicense();
public void postScreenshotToFacebook(java.lang.String, int, int, int[]); public void postScreenshotToFacebook(java.lang.String, int, int, int[]);
public int getKeyFromKeyCode(int, int, int); public int getKeyFromKeyCode(int, int, int);
public void quit(); public void quit();
public void displayDialog(int); public void displayDialog(int);
public void tick(); public void tick();
public java.lang.String[] getOptionStrings(); public java.lang.String[] getOptionStrings();
public void buyGame(); public void buyGame();
public boolean isTouchscreen(); public boolean isTouchscreen();
public void setIsPowerVR(boolean); public void setIsPowerVR(boolean);
public void initiateUserInput(int); public void initiateUserInput(int);
public int getUserInputStatus(); public int getUserInputStatus();
public java.lang.String[] getUserInputString(); public java.lang.String[] getUserInputString();
public void vibrate(int); public void vibrate(int);
} }
-keep class * implements android.os.Parcelable { -keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *; public static final android.os.Parcelable$Creator *;
} }

View File

@@ -1,4 +1,4 @@
<bitmap xmlns:android="http://schemas.android.com/apk/res/android" <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/bg32" android:src="@drawable/bg32"
android:tileMode="repeat" android:tileMode="repeat"
android:dither="false" /> android:dither="false" />

View File

@@ -1,5 +1,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/cancel_1_3" <item android:drawable="@drawable/cancel_1_3"
android:state_pressed="true" /> android:state_pressed="true" />
<item android:drawable="@drawable/cancel_0_3" /> <item android:drawable="@drawable/cancel_0_3" />
</selector> </selector>

View File

@@ -1,5 +1,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/create_1_3" <item android:drawable="@drawable/create_1_3"
android:state_pressed="true" /> android:state_pressed="true" />
<item android:drawable="@drawable/create_0_3" /> <item android:drawable="@drawable/create_0_3" />
</selector> </selector>

View File

@@ -1,5 +1,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" <item android:state_checked="true"
android:drawable="@drawable/survival_3" /> android:drawable="@drawable/survival_3" />
<item android:drawable="@drawable/creative_3" /> <item android:drawable="@drawable/creative_3" />
</selector> </selector>

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:background="@drawable/bgtiled" android:background="@drawable/bgtiled"
android:tileMode="repeat" > android:tileMode="repeat" >
<TextView android:text="Multiplayer username" <TextView android:text="Multiplayer username"
android:layout_width="540px" android:layout_width="540px"
android:layout_height="24dp" /> android:layout_height="24dp" />
<EditText android:id="@+id/editText_options_mpusername" <EditText android:id="@+id/editText_options_mpusername"
android:text="" android:text=""
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:singleLine="true" android:singleLine="true"
android:inputType="textNoSuggestions" android:inputType="textNoSuggestions"
> >
</EditText> </EditText>
</LinearLayout> </LinearLayout>

View File

@@ -1,29 +1,29 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/bgtiled" android:background="@drawable/bgtiled"
android:tileMode="repeat" android:tileMode="repeat"
android:gravity="center_horizontal" android:gravity="center_horizontal"
> >
<TextView android:text = "@string/renameworld_title" <TextView android:text = "@string/renameworld_title"
android:layout_width="360dp" android:layout_width="360dp"
android:layout_height="24dp" android:layout_height="24dp"
android:typeface="monospace" android:typeface="monospace"
/> />
<com.mojang.android.EditTextAscii <com.mojang.android.EditTextAscii
android:id="@+id/editText_worldNameRename" android:id="@+id/editText_worldNameRename"
android:text="@string/renameworld_saved_world" android:text="@string/renameworld_saved_world"
android:layout_width="360dp" android:layout_width="360dp"
android:layout_height="48dp" android:layout_height="48dp"
android:singleLine="true" android:singleLine="true"
android:typeface="monospace" android:typeface="monospace"
android:maxLength="64" android:maxLength="64"
android:imeActionLabel="Ok" android:imeActionLabel="Ok"
android:inputType="textNoSuggestions" android:inputType="textNoSuggestions"
android:imeOptions="actionDone" /> android:imeOptions="actionDone" />
<View <View
android:layout_width="360dp" android:layout_width="360dp"
android:layout_height="10px" /> android:layout_height="10px" />
</LinearLayout> </LinearLayout>

View File

@@ -1,40 +1,40 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">Minecraft - Pocket Edition</string> <string name="app_name">Minecraft - Pocket Edition</string>
<string name="app_name_demo">Minecraft - Pocket Edition Demo</string> <string name="app_name_demo">Minecraft - Pocket Edition Demo</string>
<string name="xperiaplayoptimized_content">true</string> <string name="xperiaplayoptimized_content">true</string>
<string name="app_name_short">Minecraft PE</string> <string name="app_name_short">Minecraft PE</string>
<string name="app_name_short_demo">Minecraft PE Demo</string> <string name="app_name_short_demo">Minecraft PE Demo</string>
<!-- CREATE NEW WORLD --> <!-- CREATE NEW WORLD -->
<string name="createworld_name">World name</string> <string name="createworld_name">World name</string>
<string name="createworld_new_world">Unnamed world</string> <string name="createworld_new_world">Unnamed world</string>
<string name="createworld_seed">World Generator seed. Leave blank for random.</string> <string name="createworld_seed">World Generator seed. Leave blank for random.</string>
<string name="createworld_seed_info">Leave blank for random seed</string> <string name="createworld_seed_info">Leave blank for random seed</string>
<string name="gamemode_survival_summary">Mobs, health and gather resources</string> <string name="gamemode_survival_summary">Mobs, health and gather resources</string>
<string name="gamemode_creative_summary">Unlimited resources and flying</string> <string name="gamemode_creative_summary">Unlimited resources and flying</string>
<!-- RENAME WORLD --> <!-- RENAME WORLD -->
<string name="renameworld_title">Save world as</string> <string name="renameworld_title">Save world as</string>
<string name="renameworld_saved_world">Saved World</string> <string name="renameworld_saved_world">Saved World</string>
<!-- MAIN MENU OPTIONS --> <!-- MAIN MENU OPTIONS -->
<string name="mmoptions_mp_username_title">Username</string> <string name="mmoptions_mp_username_title">Username</string>
<string name="mmoptions_mp_username_dialog">Enter your username</string> <string name="mmoptions_mp_username_dialog">Enter your username</string>
<string name="mmoptions_mp_server_visible_default_title">Server visible by default</string> <string name="mmoptions_mp_server_visible_default_title">Server visible by default</string>
<string name="mmoptions_ctrl_sensitivity_title">Sensitivity</string> <string name="mmoptions_ctrl_sensitivity_title">Sensitivity</string>
<string name="mmoptions_ctrl_invertmouse_title">Invert Y-axis</string> <string name="mmoptions_ctrl_invertmouse_title">Invert Y-axis</string>
<string name="mmoptions_ctrl_islefthanded_title">Lefty</string> <string name="mmoptions_ctrl_islefthanded_title">Lefty</string>
<string name="mmoptions_ctrl_usetouchscreen_title">Use touch screen</string> <string name="mmoptions_ctrl_usetouchscreen_title">Use touch screen</string>
<string name="mmoptions_ctrl_usetouchjoypad_title">Split touch controls</string> <string name="mmoptions_ctrl_usetouchjoypad_title">Split touch controls</string>
<string name="mmoptions_feedback_vibration_title">Vibration</string> <string name="mmoptions_feedback_vibration_title">Vibration</string>
<string name="mmoptions_feedback_vibration_summary">Slight vibration when blocks are destroyed</string> <string name="mmoptions_feedback_vibration_summary">Slight vibration when blocks are destroyed</string>
<string name="mmoptions_gfx_fancygraphics_title">Fancy graphics</string> <string name="mmoptions_gfx_fancygraphics_title">Fancy graphics</string>
<string name="mmoptions_gfx_fancygraphics_summary"></string> <string name="mmoptions_gfx_fancygraphics_summary"></string>
<string name="mmoptions_gfx_fancygraphics_summary_powervr"></string> <string name="mmoptions_gfx_fancygraphics_summary_powervr"></string>
<string name="mmoptions_gfx_lowquality_title">Lower graphics quality</string> <string name="mmoptions_gfx_lowquality_title">Lower graphics quality</string>
<string name="mmoptions_gfx_lowquality_summary">Shorter view distance and disables fancy rendering</string> <string name="mmoptions_gfx_lowquality_summary">Shorter view distance and disables fancy rendering</string>
<string name="mmoptions_game_difficultypeaceful_title">Peaceful mode</string> <string name="mmoptions_game_difficultypeaceful_title">Peaceful mode</string>
<string name="mmoptions_game_difficultypeaceful_summary">No hostile mobs, heal automatically</string> <string name="mmoptions_game_difficultypeaceful_summary">No hostile mobs, heal automatically</string>
</resources> </resources>

View File

@@ -1,105 +1,105 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory <PreferenceCategory
android:title="Multiplayer"> android:title="Multiplayer">
<EditTextPreference <EditTextPreference
android:key="mp_username" android:key="mp_username"
android:title="@string/mmoptions_mp_username_title" android:title="@string/mmoptions_mp_username_title"
android:summary="" android:summary=""
android:dialogTitle="@string/mmoptions_mp_username_dialog" android:dialogTitle="@string/mmoptions_mp_username_dialog"
android:defaultValue="Steve" android:defaultValue="Steve"
android:singleLine="true" /> android:singleLine="true" />
<CheckBoxPreference <CheckBoxPreference
android:key="mp_server_visible_default" android:key="mp_server_visible_default"
android:title="@string/mmoptions_mp_server_visible_default_title" android:title="@string/mmoptions_mp_server_visible_default_title"
android:summary="" android:summary=""
android:defaultValue="true" android:defaultValue="true"
/> />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:key="category_graphics" android:key="category_graphics"
android:title="Graphics"> android:title="Graphics">
<CheckBoxPreference <CheckBoxPreference
android:key="gfx_fancygraphics" android:key="gfx_fancygraphics"
android:title="@string/mmoptions_gfx_fancygraphics_title" android:title="@string/mmoptions_gfx_fancygraphics_title"
android:summary="@string/mmoptions_gfx_fancygraphics_summary" android:summary="@string/mmoptions_gfx_fancygraphics_summary"
android:defaultValue="false" android:defaultValue="false"
/> />
<CheckBoxPreference <CheckBoxPreference
android:key="gfx_lowquality" android:key="gfx_lowquality"
android:title="@string/mmoptions_gfx_lowquality_title" android:title="@string/mmoptions_gfx_lowquality_title"
android:summary="@string/mmoptions_gfx_lowquality_summary" android:summary="@string/mmoptions_gfx_lowquality_summary"
android:defaultValue="false" android:defaultValue="false"
/> />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="Controls"> android:title="Controls">
<com.mojang.android.preferences.SliderPreference <com.mojang.android.preferences.SliderPreference
android:key="ctrl_sensitivity" android:key="ctrl_sensitivity"
android:title="@string/mmoptions_ctrl_sensitivity_title" android:title="@string/mmoptions_ctrl_sensitivity_title"
android:max="100" android:max="100"
android:summary="" android:summary=""
android:defaultValue="50" android:defaultValue="50"
android:enabled="true" android:enabled="true"
/> />
<CheckBoxPreference <CheckBoxPreference
android:key="ctrl_invertmouse" android:key="ctrl_invertmouse"
android:title="@string/mmoptions_ctrl_invertmouse_title" android:title="@string/mmoptions_ctrl_invertmouse_title"
android:summary="" android:summary=""
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
/> />
<CheckBoxPreference <CheckBoxPreference
android:key="ctrl_islefthanded" android:key="ctrl_islefthanded"
android:title="@string/mmoptions_ctrl_islefthanded_title" android:title="@string/mmoptions_ctrl_islefthanded_title"
android:summary="" android:summary=""
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
/> />
<CheckBoxPreference <CheckBoxPreference
android:key="ctrl_usetouchscreen" android:key="ctrl_usetouchscreen"
android:title="@string/mmoptions_ctrl_usetouchscreen_title" android:title="@string/mmoptions_ctrl_usetouchscreen_title"
android:summary="" android:summary=""
android:defaultValue="true" android:defaultValue="true"
android:enabled="false" android:enabled="false"
/> />
<CheckBoxPreference <CheckBoxPreference
android:key="ctrl_usetouchjoypad" android:key="ctrl_usetouchjoypad"
android:title="@string/mmoptions_ctrl_usetouchjoypad_title" android:title="@string/mmoptions_ctrl_usetouchjoypad_title"
android:summary="" android:summary=""
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
/> />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="Feedback"> android:title="Feedback">
<CheckBoxPreference <CheckBoxPreference
android:key="feedback_vibration" android:key="feedback_vibration"
android:title="@string/mmoptions_feedback_vibration_title" android:title="@string/mmoptions_feedback_vibration_title"
android:summary="@string/mmoptions_feedback_vibration_summary" android:summary="@string/mmoptions_feedback_vibration_summary"
android:defaultValue="true" android:defaultValue="true"
android:enabled="true" android:enabled="true"
/> />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="Game"> android:title="Game">
<CheckBoxPreference <CheckBoxPreference
android:key="game_difficultypeaceful" android:key="game_difficultypeaceful"
android:title="@string/mmoptions_game_difficultypeaceful_title" android:title="@string/mmoptions_game_difficultypeaceful_title"
android:summary="@string/mmoptions_game_difficultypeaceful_summary" android:summary="@string/mmoptions_game_difficultypeaceful_summary"
android:defaultValue="false" android:defaultValue="false"
/> />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@@ -1,58 +1,58 @@
package com.mojang.android; package com.mojang.android;
import android.content.Context; import android.content.Context;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.EditText; import android.widget.EditText;
public class EditTextAscii extends EditText public class EditTextAscii extends EditText
implements TextWatcher { implements TextWatcher {
public EditTextAscii(Context context) { public EditTextAscii(Context context) {
super(context); super(context);
_init(); _init();
} }
public EditTextAscii(Context context, AttributeSet attrs) { public EditTextAscii(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
_init(); _init();
} }
public EditTextAscii(Context context, AttributeSet attrs, int defStyle) { public EditTextAscii(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
_init(); _init();
} }
private void _init() { private void _init() {
this.addTextChangedListener(this); this.addTextChangedListener(this);
} }
// //
// TextWatcher // TextWatcher
// //
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, int count) {} public void onTextChanged(CharSequence s, int start, int before, int count) {}
//@Override //@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
//@Override //@Override
public void afterTextChanged(Editable e) { public void afterTextChanged(Editable e) {
String s = e.toString(); String s = e.toString();
String sanitized = sanitize(s); String sanitized = sanitize(s);
if (!s.equals(sanitized)) { if (!s.equals(sanitized)) {
e.replace(0, e.length(), sanitized); e.replace(0, e.length(), sanitized);
} }
} }
static public String sanitize(String s) { static public String sanitize(String s) {
StringBuilder sb = new StringBuilder(s.length()); StringBuilder sb = new StringBuilder(s.length());
for (int i = 0; i < s.length(); ++i) { for (int i = 0; i < s.length(); ++i) {
char ch = s.charAt(i); char ch = s.charAt(i);
if (ch < 128) if (ch < 128)
sb.append(ch); sb.append(ch);
} }
return sb.toString(); return sb.toString();
} }
} }

View File

@@ -1,5 +1,5 @@
package com.mojang.android; package com.mojang.android;
public interface StringValue { public interface StringValue {
public String getStringValue(); public String getStringValue();
} }

View File

@@ -1,29 +1,29 @@
package com.mojang.android.licensing; package com.mojang.android.licensing;
///see LicenseResult.h in C++ project ///see LicenseResult.h in C++ project
public class LicenseCodes { public class LicenseCodes {
// Something's not ready, call again later // Something's not ready, call again later
public static final int WAIT_PLATFORM_NOT_READY = -2; // Note used from java public static final int WAIT_PLATFORM_NOT_READY = -2; // Note used from java
public static final int WAIT_SERVER_NOT_READY = -1; public static final int WAIT_SERVER_NOT_READY = -1;
// License is ok // License is ok
public static final int LICENSE_OK = 0; public static final int LICENSE_OK = 0;
public static final int LICENSE_TRIAL_OK = 1; public static final int LICENSE_TRIAL_OK = 1;
// License is not working in one way or another // License is not working in one way or another
public static final int LICENSE_VALIDATION_FAILED = 50; public static final int LICENSE_VALIDATION_FAILED = 50;
public static final int ITEM_NOT_FOUND = 51; public static final int ITEM_NOT_FOUND = 51;
public static final int LICENSE_NOT_FOUND = 52; public static final int LICENSE_NOT_FOUND = 52;
public static final int ERROR_CONTENT_HANDLER = 100; public static final int ERROR_CONTENT_HANDLER = 100;
public static final int ERROR_ILLEGAL_ARGUMENT = 101; public static final int ERROR_ILLEGAL_ARGUMENT = 101;
public static final int ERROR_SECURITY = 102; public static final int ERROR_SECURITY = 102;
public static final int ERROR_INPUT_OUTPUT = 103; public static final int ERROR_INPUT_OUTPUT = 103;
public static final int ERROR_ILLEGAL_STATE = 104; public static final int ERROR_ILLEGAL_STATE = 104;
public static final int ERROR_NULL_POINTER = 105; public static final int ERROR_NULL_POINTER = 105;
public static final int ERROR_GENERAL = 106; public static final int ERROR_GENERAL = 106;
public static final int ERROR_UNABLE_TO_CONNECT_TO_CDS = 107; public static final int ERROR_UNABLE_TO_CONNECT_TO_CDS = 107;
// The call went wrong so we didn't get a license value at all // The call went wrong so we didn't get a license value at all
public static final int LICENSE_CHECK_EXCEPTION = 200; public static final int LICENSE_CHECK_EXCEPTION = 200;
} }

View File

@@ -1,233 +1,233 @@
package com.mojang.android.preferences; package com.mojang.android.preferences;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.preference.DialogPreference; import android.preference.DialogPreference;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
public class SliderPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener { public class SliderPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener {
private static final String androidns = "http://schemas.android.com/apk/res/android"; private static final String androidns = "http://schemas.android.com/apk/res/android";
private Context _context; private Context _context;
//private TextView _minValueTextView; //private TextView _minValueTextView;
private TextView _valueTextView; private TextView _valueTextView;
//private TextView _maxValueTextView; //private TextView _maxValueTextView;
private SeekBar _seekBar; private SeekBar _seekBar;
private String _valueSuffix; private String _valueSuffix;
private int _defaultValue; // Stores the default preference value when none has been set private int _defaultValue; // Stores the default preference value when none has been set
private int _maxValue; // Stores the upper preference value bound private int _maxValue; // Stores the upper preference value bound
private int _value; // Stores the value of the preference private int _value; // Stores the value of the preference
private int _minValue; // Stores the minimum preference value bound private int _minValue; // Stores the minimum preference value bound
public SliderPreference(Context context, AttributeSet attrs) { public SliderPreference(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
_context = context; _context = context;
_valueSuffix = getResourceValueFromAttribute(attrs, androidns, "text", ""); _valueSuffix = getResourceValueFromAttribute(attrs, androidns, "text", "");
_defaultValue = getResourceValueFromAttribute(attrs, androidns, "defaultValue", 0); _defaultValue = getResourceValueFromAttribute(attrs, androidns, "defaultValue", 0);
_maxValue = getResourceValueFromAttribute(attrs, androidns, "max", 100); _maxValue = getResourceValueFromAttribute(attrs, androidns, "max", 100);
_minValue = getResourceValueFromAttribute(attrs, null, "min", 0); _minValue = getResourceValueFromAttribute(attrs, null, "min", 0);
// Set the default value of the preference to the default value found in attribute // Set the default value of the preference to the default value found in attribute
setDefaultValue((Integer) _defaultValue); setDefaultValue((Integer) _defaultValue);
} }
//public SliderPreference(Context context, AttributeSet attrs, int) //public SliderPreference(Context context, AttributeSet attrs, int)
@Override @Override
protected View onCreateDialogView() { protected View onCreateDialogView() {
LinearLayout.LayoutParams params; LinearLayout.LayoutParams params;
LinearLayout layout = new LinearLayout(getContext()); LinearLayout layout = new LinearLayout(getContext());
layout.setOrientation(LinearLayout.VERTICAL); layout.setOrientation(LinearLayout.VERTICAL);
layout.setPadding(6,6,6,6); layout.setPadding(6,6,6,6);
// mSplashText = new TextView(_context); // mSplashText = new TextView(_context);
// if (mDialogMessage != null) // if (mDialogMessage != null)
// mSplashText.setText(mDialogMessage); // mSplashText.setText(mDialogMessage);
// layout.addView(mSplashText); // layout.addView(mSplashText);
_valueTextView = new TextView(_context); _valueTextView = new TextView(_context);
_valueTextView.setGravity(Gravity.CENTER_HORIZONTAL); _valueTextView.setGravity(Gravity.CENTER_HORIZONTAL);
_valueTextView.setTextSize(32); _valueTextView.setTextSize(32);
params = new LinearLayout.LayoutParams( params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT); LinearLayout.LayoutParams.WRAP_CONTENT);
layout.addView(_valueTextView, params); layout.addView(_valueTextView, params);
_seekBar = new SeekBar(_context); _seekBar = new SeekBar(_context);
_seekBar.setOnSeekBarChangeListener(this); _seekBar.setOnSeekBarChangeListener(this);
layout.addView(_seekBar, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); layout.addView(_seekBar, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
if (shouldPersist()) if (shouldPersist())
_value = getPersistedInt(_defaultValue); _value = getPersistedInt(_defaultValue);
_seekBar.setMax(_maxValue); _seekBar.setMax(_maxValue);
_seekBar.setProgress(_value); _seekBar.setProgress(_value);
return layout; return layout;
} }
@Override @Override
protected void onSetInitialValue(boolean restore, Object defaultValue) { protected void onSetInitialValue(boolean restore, Object defaultValue) {
super.onSetInitialValue(restore, defaultValue); super.onSetInitialValue(restore, defaultValue);
if (restore) if (restore)
_value = shouldPersist() ? getPersistedInt(_defaultValue) : 0; _value = shouldPersist() ? getPersistedInt(_defaultValue) : 0;
else else
_value = (Integer) defaultValue; _value = (Integer) defaultValue;
} }
/* /*
@Override @Override
protected void onBindView(View view) { protected void onBindView(View view) {
super.onBindView(view); super.onBindView(view);
// Bind _seekBar to the layout's internal view // Bind _seekBar to the layout's internal view
_seekBar = (SeekBar) view.findViewById(R.id.slider_preference_seekbar); _seekBar = (SeekBar) view.findViewById(R.id.slider_preference_seekbar);
// Setup it's listeners and parameters // Setup it's listeners and parameters
_seekBar.setMax(translateValueToSeekBar(_maxValue)); _seekBar.setMax(translateValueToSeekBar(_maxValue));
_seekBar.setProgress(translateValueToSeekBar(_value)); _seekBar.setProgress(translateValueToSeekBar(_value));
_seekBar.setOnSeekBarChangeListener(this); _seekBar.setOnSeekBarChangeListener(this);
// Bind mTextView to the layout's internal view // Bind mTextView to the layout's internal view
_valueTextView = (TextView) view.findViewById(R.id.slider_preference_value); _valueTextView = (TextView) view.findViewById(R.id.slider_preference_value);
// Setup it's parameters // Setup it's parameters
_valueTextView.setText(getValueText(_value)); _valueTextView.setText(getValueText(_value));
// Setup min and max value text views // Setup min and max value text views
_minValueTextView = (TextView) view.findViewById(R.id.slider_preference_min_value); _minValueTextView = (TextView) view.findViewById(R.id.slider_preference_min_value);
_minValueTextView.setText(getValueText(_minValue)); _minValueTextView.setText(getValueText(_minValue));
_maxValueTextView = (TextView) view.findViewById(R.id.slider_preference_max_value); _maxValueTextView = (TextView) view.findViewById(R.id.slider_preference_max_value);
_maxValueTextView.setText(getValueText(_maxValue)); _maxValueTextView.setText(getValueText(_maxValue));
} }
*/ */
//@Override //@Override
public void onProgressChanged(SeekBar seekBar, int value, boolean fromUser) { public void onProgressChanged(SeekBar seekBar, int value, boolean fromUser) {
// Change mTextView and _value to the current seekbar value // Change mTextView and _value to the current seekbar value
_value = translateValueFro_seekBar(value); _value = translateValueFro_seekBar(value);
_valueTextView.setText(getValueText(_value)); _valueTextView.setText(getValueText(_value));
if (shouldPersist()) if (shouldPersist())
persistInt(translateValueFro_seekBar(value)); persistInt(translateValueFro_seekBar(value));
callChangeListener(new Integer(_value)); callChangeListener(new Integer(_value));
} }
//@Override //@Override
public void onStartTrackingTouch(SeekBar seekBar) { public void onStartTrackingTouch(SeekBar seekBar) {
// Not used // Not used
} }
//@Override //@Override
public void onStopTrackingTouch(SeekBar seekBar) { public void onStopTrackingTouch(SeekBar seekBar) {
// Not used // Not used
} }
private String getValueText(int value) { private String getValueText(int value) {
String t = String.valueOf(value); String t = String.valueOf(value);
return t.concat(_valueSuffix); return t.concat(_valueSuffix);
} }
/** /**
* Retrieves a value from the resources of this slider preference's context * Retrieves a value from the resources of this slider preference's context
* based on an attribute pointing to that resource. * based on an attribute pointing to that resource.
* *
* @param attrs * @param attrs
* The attribute set to search * The attribute set to search
* *
* @param namespace * @param namespace
* The namespace of the attribute * The namespace of the attribute
* *
* @param name * @param name
* The name of the attribute * The name of the attribute
* *
* @param defaultValue * @param defaultValue
* The default value returned if no resource is found * The default value returned if no resource is found
* *
* @return * @return
* The resource value * The resource value
*/ */
private int getResourceValueFromAttribute(AttributeSet attrs, String namespace, String name, int defaultValue) { private int getResourceValueFromAttribute(AttributeSet attrs, String namespace, String name, int defaultValue) {
Resources res = getContext().getResources(); Resources res = getContext().getResources();
int valueID = attrs.getAttributeResourceValue(namespace, name, 0); int valueID = attrs.getAttributeResourceValue(namespace, name, 0);
if (valueID != 0) { if (valueID != 0) {
return res.getInteger(valueID); return res.getInteger(valueID);
} }
else { else {
return attrs.getAttributeIntValue(namespace, name, defaultValue); return attrs.getAttributeIntValue(namespace, name, defaultValue);
} }
} }
/** /**
* Retrieves a value from the resources of this slider preference's context * Retrieves a value from the resources of this slider preference's context
* based on an attribute pointing to that resource. * based on an attribute pointing to that resource.
* *
* @param attrs * @param attrs
* The attribute set to search * The attribute set to search
* *
* @param namespace * @param namespace
* The namespace of the attribute * The namespace of the attribute
* *
* @param name * @param name
* The name of the attribute * The name of the attribute
* *
* @param defaultValue * @param defaultValue
* The default value returned if no resource is found * The default value returned if no resource is found
* *
* @return * @return
* The resource value * The resource value
*/ */
private String getResourceValueFromAttribute(AttributeSet attrs, String namespace, String name, String defaultValue) { private String getResourceValueFromAttribute(AttributeSet attrs, String namespace, String name, String defaultValue) {
Resources res = getContext().getResources(); Resources res = getContext().getResources();
int valueID = attrs.getAttributeResourceValue(namespace, name, 0); int valueID = attrs.getAttributeResourceValue(namespace, name, 0);
if (valueID != 0) { if (valueID != 0) {
return res.getString(valueID); return res.getString(valueID);
} }
else { else {
String value = attrs.getAttributeValue(namespace, name); String value = attrs.getAttributeValue(namespace, name);
if (value != null) { if (value != null) {
return value; return value;
} }
else { else {
return defaultValue; return defaultValue;
} }
} }
} }
/** /**
* Translates a value from this slider preference's seekbar by * Translates a value from this slider preference's seekbar by
* adjusting it for a set perceived minimum value. * adjusting it for a set perceived minimum value.
* *
* @param value * @param value
* The value to be translated from the seekbar * The value to be translated from the seekbar
* *
* @return * @return
* A value equal to the value passed plus the currently set minimum value. * A value equal to the value passed plus the currently set minimum value.
*/ */
private int translateValueFro_seekBar(int value) { private int translateValueFro_seekBar(int value) {
return value + _minValue; return value + _minValue;
} }
/** /**
* Translates a value for when setting this slider preference's seekbar by * Translates a value for when setting this slider preference's seekbar by
* adjusting it for a set perceived minimum value. * adjusting it for a set perceived minimum value.
* *
* @param value * @param value
* The value to be translated for use * The value to be translated for use
* *
* @return * @return
* A value equal to the value passed minus the currently set minimum value. * A value equal to the value passed minus the currently set minimum value.
*/ */
private int translateValueToSeekBar(int value) { private int translateValueToSeekBar(int value) {
return value - _minValue; return value - _minValue;
} }
} }

View File

@@ -1,77 +1,77 @@
package com.mojang.minecraftpe; package com.mojang.minecraftpe;
import com.mojang.android.StringValue; import com.mojang.android.StringValue;
import com.mojang.minecraftpe.R; import com.mojang.minecraftpe.R;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.widget.TextView; import android.widget.TextView;
import android.widget.ToggleButton; import android.widget.ToggleButton;
public class GameModeButton extends ToggleButton implements OnClickListener, StringValue { public class GameModeButton extends ToggleButton implements OnClickListener, StringValue {
public GameModeButton(Context context, AttributeSet attrs) { public GameModeButton(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
_init(); _init();
} }
//@Override //@Override
public void onClick(View v) { public void onClick(View v) {
_update(); _update();
} }
@Override @Override
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
_update(); _update();
} }
@Override @Override
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
if (!_attached) { if (!_attached) {
_update(); _update();
_attached = true; _attached = true;
} }
} }
private boolean _attached = false; private boolean _attached = false;
private void _init() { private void _init() {
setOnClickListener(this); setOnClickListener(this);
} }
private void _update() { private void _update() {
_setGameType(isChecked()?Survival:Creative); _setGameType(isChecked()?Survival:Creative);
} }
private void _setGameType(int i) { private void _setGameType(int i) {
_type = _clamp(i); _type = _clamp(i);
int id = R.string.gamemode_creative_summary; int id = R.string.gamemode_creative_summary;
if (_type == Survival) if (_type == Survival)
id = R.string.gamemode_survival_summary; id = R.string.gamemode_survival_summary;
String desc = getContext().getString(id); String desc = getContext().getString(id);
View v = getRootView().findViewById(R.id.labelGameModeDesc); View v = getRootView().findViewById(R.id.labelGameModeDesc);
System.out.println("Mode: " + _type + ", view? " + (v!=null)); System.out.println("Mode: " + _type + ", view? " + (v!=null));
if (desc != null && v != null && v instanceof TextView) { if (desc != null && v != null && v instanceof TextView) {
((TextView)v).setText(desc); ((TextView)v).setText(desc);
} }
} }
static private int _clamp(int i) { static private int _clamp(int i) {
if (i > Survival) return Survival; if (i > Survival) return Survival;
if (i < Creative) return Creative; if (i < Creative) return Creative;
return i; return i;
} }
public String getStringValue() { public String getStringValue() {
return getStringForType(_type); return getStringForType(_type);
} }
static public String getStringForType(int i) { static public String getStringForType(int i) {
return new String[] { return new String[] {
"creative", "creative",
"survival" "survival"
} [_clamp(i)]; } [_clamp(i)];
} }
private int _type = 0; private int _type = 0;
static final int Creative = 0; static final int Creative = 0;
static final int Survival = 1; static final int Survival = 1;
} }

View File

@@ -1,197 +1,197 @@
package com.mojang.minecraftpe; package com.mojang.minecraftpe;
import java.util.ArrayList; import java.util.ArrayList;
import com.mojang.android.EditTextAscii; import com.mojang.android.EditTextAscii;
//import com.mojang.minecraftpe.R; //import com.mojang.minecraftpe.R;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.os.Bundle; import android.os.Bundle;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference; import android.preference.EditTextPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory; import android.preference.PreferenceCategory;
import android.preference.PreferenceGroup; import android.preference.PreferenceGroup;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
public class MainMenuOptionsActivity extends PreferenceActivity implements public class MainMenuOptionsActivity extends PreferenceActivity implements
SharedPreferences.OnSharedPreferenceChangeListener SharedPreferences.OnSharedPreferenceChangeListener
{ {
static public final String Multiplayer_Username = "mp_username"; static public final String Multiplayer_Username = "mp_username";
static public final String Multiplayer_ServerVisible = "mp_server_visible_default"; static public final String Multiplayer_ServerVisible = "mp_server_visible_default";
static public final String Graphics_Fancy = "gfx_fancygraphics"; static public final String Graphics_Fancy = "gfx_fancygraphics";
static public final String Graphics_LowQuality = "gfx_lowquality"; static public final String Graphics_LowQuality = "gfx_lowquality";
static public final String Controls_InvertMouse = "ctrl_invertmouse"; static public final String Controls_InvertMouse = "ctrl_invertmouse";
static public final String Controls_Sensitivity = "ctrl_sensitivity"; static public final String Controls_Sensitivity = "ctrl_sensitivity";
static public final String Controls_UseTouchscreen = "ctrl_usetouchscreen"; static public final String Controls_UseTouchscreen = "ctrl_usetouchscreen";
static public final String Controls_UseTouchJoypad = "ctrl_usetouchjoypad"; static public final String Controls_UseTouchJoypad = "ctrl_usetouchjoypad";
static public final String Controls_FeedbackVibration = "feedback_vibration"; static public final String Controls_FeedbackVibration = "feedback_vibration";
static public final String Game_DifficultyLevel = "game_difficulty"; static public final String Game_DifficultyLevel = "game_difficulty";
static public final String Internal_Game_DifficultyPeaceful = "game_difficultypeaceful"; static public final String Internal_Game_DifficultyPeaceful = "game_difficultypeaceful";
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
addPreferencesFromResource(extras.getInt("preferenceId"));//R.xml.preferences); addPreferencesFromResource(extras.getInt("preferenceId"));//R.xml.preferences);
//getPreferenceManager().setSharedPreferencesMode(MODE_PRIVATE); //getPreferenceManager().setSharedPreferencesMode(MODE_PRIVATE);
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this); PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
PreferenceScreen s = getPreferenceScreen(); PreferenceScreen s = getPreferenceScreen();
if (PreferenceManager.getDefaultSharedPreferences(this).contains(Multiplayer_Username)) { if (PreferenceManager.getDefaultSharedPreferences(this).contains(Multiplayer_Username)) {
previousName = PreferenceManager.getDefaultSharedPreferences(this).getString(Multiplayer_Username, null); previousName = PreferenceManager.getDefaultSharedPreferences(this).getString(Multiplayer_Username, null);
} }
_validator = new PreferenceValidator(this); _validator = new PreferenceValidator(this);
readBackAll(s); readBackAll(s);
_validator.commit(); _validator.commit();
} }
private void readBackAll(PreferenceGroup g) { private void readBackAll(PreferenceGroup g) {
traversePreferences(g, new PreferenceTraverser() { traversePreferences(g, new PreferenceTraverser() {
void onPreference(Preference p) { readBack(p); _validator.validate(p); } void onPreference(Preference p) { readBack(p); _validator.validate(p); }
}); });
} }
private void traversePreferences(PreferenceGroup g, PreferenceTraverser pt) { private void traversePreferences(PreferenceGroup g, PreferenceTraverser pt) {
int size = g.getPreferenceCount(); int size = g.getPreferenceCount();
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
Preference p = g.getPreference(i); Preference p = g.getPreference(i);
if (p instanceof PreferenceGroup) { if (p instanceof PreferenceGroup) {
PreferenceGroup pg = (PreferenceGroup)p; PreferenceGroup pg = (PreferenceGroup)p;
pt.onPreferenceGroup(pg); pt.onPreferenceGroup(pg);
traversePreferences(pg, pt); traversePreferences(pg, pt);
} }
else else
pt.onPreference(p); pt.onPreference(p);
} }
} }
private void readBack(Preference p) { private void readBack(Preference p) {
if (p == null) if (p == null)
return; return;
//System.out.println("pref: " + p.toString()); //System.out.println("pref: " + p.toString());
if (p instanceof EditTextPreference) { if (p instanceof EditTextPreference) {
EditTextPreference e = (EditTextPreference) p; EditTextPreference e = (EditTextPreference) p;
p.setSummary("'" + e.getText() + "'"); p.setSummary("'" + e.getText() + "'");
} }
} }
//@Override //@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference p = findPreference(key); Preference p = findPreference(key);
_validator.validate(sharedPreferences, key); _validator.validate(sharedPreferences, key);
if (p instanceof EditTextPreference) { if (p instanceof EditTextPreference) {
EditTextPreference e = (EditTextPreference) p; EditTextPreference e = (EditTextPreference) p;
Editor editor = sharedPreferences.edit(); Editor editor = sharedPreferences.edit();
String s = e.getText(); String s = e.getText();
String sanitized = EditTextAscii.sanitize(s).trim(); String sanitized = EditTextAscii.sanitize(s).trim();
if (key.equals(Multiplayer_Username) && sanitized == null || sanitized.length() == 0) { if (key.equals(Multiplayer_Username) && sanitized == null || sanitized.length() == 0) {
sanitized = previousName; sanitized = previousName;
if (sanitized == null || sanitized.equals("")) { if (sanitized == null || sanitized.equals("")) {
sanitized = "Steve"; sanitized = "Steve";
previousName = sanitized; previousName = sanitized;
} }
} }
if (!s.equals(sanitized)) { if (!s.equals(sanitized)) {
editor.putString(key, sanitized); editor.putString(key, sanitized);
editor.commit(); editor.commit();
e.setText(sanitized); e.setText(sanitized);
} }
} }
readBack(p); readBack(p);
} }
String previousName; String previousName;
PreferenceValidator _validator; PreferenceValidator _validator;
} }
class PreferenceValidator { class PreferenceValidator {
static private class Pref { static private class Pref {
Pref(PreferenceGroup g, Preference p) { Pref(PreferenceGroup g, Preference p) {
this.g = g; this.g = g;
this.p = p; this.p = p;
} }
PreferenceGroup g; PreferenceGroup g;
Preference p; Preference p;
} }
private PreferenceActivity _prefs; private PreferenceActivity _prefs;
private ArrayList<Pref> _arrayList = new ArrayList<Pref>(); private ArrayList<Pref> _arrayList = new ArrayList<Pref>();
public PreferenceValidator(PreferenceActivity prefs) { public PreferenceValidator(PreferenceActivity prefs) {
_prefs = prefs; _prefs = prefs;
} }
public void commit() { public void commit() {
//System.err.println("ERR: " + _arrayList.size()); //System.err.println("ERR: " + _arrayList.size());
for (int i = 0; i < _arrayList.size(); ++i) { for (int i = 0; i < _arrayList.size(); ++i) {
PreferenceGroup g = _arrayList.get(i).g; PreferenceGroup g = _arrayList.get(i).g;
Preference p = _arrayList.get(i).p; Preference p = _arrayList.get(i).p;
g.removePreference(p); g.removePreference(p);
} }
} }
public void validate(Preference p) { public void validate(Preference p) {
validate(PreferenceManager.getDefaultSharedPreferences(_prefs), p.getKey()); validate(PreferenceManager.getDefaultSharedPreferences(_prefs), p.getKey());
} }
public void validate(SharedPreferences preferences, String key) { public void validate(SharedPreferences preferences, String key) {
Preference p = findPreference(key); Preference p = findPreference(key);
if (p instanceof CheckBoxPreference) { if (p instanceof CheckBoxPreference) {
//CheckBoxPreference e = (CheckBoxPreference) p; //CheckBoxPreference e = (CheckBoxPreference) p;
if (key.equals(MainMenuOptionsActivity.Graphics_LowQuality)) { if (key.equals(MainMenuOptionsActivity.Graphics_LowQuality)) {
boolean isShort = preferences.getBoolean(MainMenuOptionsActivity.Graphics_LowQuality, false); boolean isShort = preferences.getBoolean(MainMenuOptionsActivity.Graphics_LowQuality, false);
CheckBoxPreference fancyPref = (CheckBoxPreference)findPreference(MainMenuOptionsActivity.Graphics_Fancy); CheckBoxPreference fancyPref = (CheckBoxPreference)findPreference(MainMenuOptionsActivity.Graphics_Fancy);
if (fancyPref != null) { if (fancyPref != null) {
fancyPref.setEnabled(isShort == false); fancyPref.setEnabled(isShort == false);
if (isShort) if (isShort)
fancyPref.setChecked(false); fancyPref.setChecked(false);
} }
} }
if (key.equals(MainMenuOptionsActivity.Graphics_Fancy)) { if (key.equals(MainMenuOptionsActivity.Graphics_Fancy)) {
CheckBoxPreference fancyPref = (CheckBoxPreference) p; CheckBoxPreference fancyPref = (CheckBoxPreference) p;
//System.err.println("Is PowerVR? : " + MainActivity.isPowerVR()); //System.err.println("Is PowerVR? : " + MainActivity.isPowerVR());
if (MainActivity.isPowerVR()) { if (MainActivity.isPowerVR()) {
fancyPref.setSummary("Experimental on this device!"); fancyPref.setSummary("Experimental on this device!");
} }
} }
if (p.getKey().equals(MainMenuOptionsActivity.Controls_UseTouchscreen)) { if (p.getKey().equals(MainMenuOptionsActivity.Controls_UseTouchscreen)) {
boolean hasOtherPrimaryControls = MainActivity.isXperiaPlay(); boolean hasOtherPrimaryControls = MainActivity.isXperiaPlay();
if (!hasOtherPrimaryControls) { if (!hasOtherPrimaryControls) {
PreferenceCategory mCategory = (PreferenceCategory) findPreference("category_graphics"); PreferenceCategory mCategory = (PreferenceCategory) findPreference("category_graphics");
_arrayList.add(new Pref(mCategory, p)); _arrayList.add(new Pref(mCategory, p));
} }
p.setEnabled(hasOtherPrimaryControls); p.setEnabled(hasOtherPrimaryControls);
p.setDefaultValue( !hasOtherPrimaryControls ); p.setDefaultValue( !hasOtherPrimaryControls );
if (hasOtherPrimaryControls) { if (hasOtherPrimaryControls) {
CheckBoxPreference pp = (CheckBoxPreference) p; CheckBoxPreference pp = (CheckBoxPreference) p;
CheckBoxPreference j = (CheckBoxPreference)findPreference(MainMenuOptionsActivity.Controls_UseTouchJoypad); CheckBoxPreference j = (CheckBoxPreference)findPreference(MainMenuOptionsActivity.Controls_UseTouchJoypad);
j.setEnabled(pp.isChecked()); j.setEnabled(pp.isChecked());
} }
} }
} }
} }
private Preference findPreference(String key) { private Preference findPreference(String key) {
return _prefs.findPreference(key); return _prefs.findPreference(key);
} }
} }
abstract class PreferenceTraverser { abstract class PreferenceTraverser {
void onPreference(Preference p) {} void onPreference(Preference p) {}
void onPreferenceGroup(PreferenceGroup p) {} void onPreferenceGroup(PreferenceGroup p) {}
} }

View File

@@ -1,14 +1,14 @@
package com.mojang.minecraftpe; package com.mojang.minecraftpe;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import com.mojang.minecraftpe.MainActivity; import com.mojang.minecraftpe.MainActivity;
public class Minecraft_Market extends MainActivity { public class Minecraft_Market extends MainActivity {
@Override @Override
public void buyGame() { public void buyGame() {
final Uri buyLink = Uri.parse("market://details?id=com.mojang.minecraftpe"); final Uri buyLink = Uri.parse("market://details?id=com.mojang.minecraftpe");
Intent marketIntent = new Intent( Intent.ACTION_VIEW, buyLink ); Intent marketIntent = new Intent( Intent.ACTION_VIEW, buyLink );
startActivity(marketIntent); startActivity(marketIntent);
} }
} }

View File

@@ -1,17 +1,17 @@
package com.mojang.minecraftpe; package com.mojang.minecraftpe;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import com.mojang.android.licensing.LicenseCodes; import com.mojang.android.licensing.LicenseCodes;
public class Minecraft_Market_Demo extends MainActivity { public class Minecraft_Market_Demo extends MainActivity {
@Override @Override
public void buyGame() { public void buyGame() {
final Uri buyLink = Uri.parse("market://details?id=com.mojang.minecraftpe"); final Uri buyLink = Uri.parse("market://details?id=com.mojang.minecraftpe");
Intent marketIntent = new Intent( Intent.ACTION_VIEW, buyLink ); Intent marketIntent = new Intent( Intent.ACTION_VIEW, buyLink );
startActivity(marketIntent); startActivity(marketIntent);
} }
@Override @Override
protected boolean isDemo() { return true; } protected boolean isDemo() { return true; }
} }

View File

@@ -1,89 +1,89 @@
package com.mojang.minecraftpe; package com.mojang.minecraftpe;
import android.os.Bundle; import android.os.Bundle;
import com.mojang.android.licensing.LicenseCodes; import com.mojang.android.licensing.LicenseCodes;
import com.verizon.vcast.apps.LicenseAuthenticator; import com.verizon.vcast.apps.LicenseAuthenticator;
public class Minecraft_Verizon extends MainActivity { public class Minecraft_Verizon extends MainActivity {
@Override @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState)
{ {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
_licenseLib = new LicenseAuthenticator(this); _licenseLib = new LicenseAuthenticator(this);
_verizonThread = new VerizonLicenseThread(_licenseLib, VCastMarketKeyword, false); _verizonThread = new VerizonLicenseThread(_licenseLib, VCastMarketKeyword, false);
_verizonThread.start(); _verizonThread.start();
} }
@Override @Override
public int checkLicense() { public int checkLicense() {
if (_verizonThread == null) if (_verizonThread == null)
return _licenseCode; return _licenseCode;
if (!_verizonThread.hasCode) if (!_verizonThread.hasCode)
return -1; return -1;
_licenseCode = _verizonThread.returnCode; _licenseCode = _verizonThread.returnCode;
_verizonThread = null; _verizonThread = null;
return _licenseCode; return _licenseCode;
} }
@Override @Override
public boolean hasBuyButtonWhenInvalidLicense() { return false; } public boolean hasBuyButtonWhenInvalidLicense() { return false; }
private LicenseAuthenticator _licenseLib; private LicenseAuthenticator _licenseLib;
private VerizonLicenseThread _verizonThread; private VerizonLicenseThread _verizonThread;
private int _licenseCode; private int _licenseCode;
static private final String VCastMarketKeyword = "Minecraft"; static private final String VCastMarketKeyword = "Minecraft";
} }
// //
// Requests license code from the Verizon VCAST application on the phone // Requests license code from the Verizon VCAST application on the phone
// //
class VerizonLicenseThread extends Thread class VerizonLicenseThread extends Thread
{ {
public VerizonLicenseThread(LicenseAuthenticator licenseLib, String keyword, boolean isTest) { public VerizonLicenseThread(LicenseAuthenticator licenseLib, String keyword, boolean isTest) {
_keyword = keyword; _keyword = keyword;
_isTest = isTest; _isTest = isTest;
_licenseLib = licenseLib; _licenseLib = licenseLib;
} }
public void run() { public void run() {
if (_isTest) if (_isTest)
validateTestLicense(); validateTestLicense();
else else
validateLicense(); validateLicense();
} }
void validateTestLicense() { void validateTestLicense() {
try { try {
//final int status = LicenseAuthenticator.LICENSE_NOT_FOUND; //final int status = LicenseAuthenticator.LICENSE_NOT_FOUND;
final int status = LicenseAuthenticator.LICENSE_OK; final int status = LicenseAuthenticator.LICENSE_OK;
returnCode = _licenseLib.checkTestLicense( _keyword, status ); returnCode = _licenseLib.checkTestLicense( _keyword, status );
} }
catch (Throwable e) { catch (Throwable e) {
returnCode = LicenseCodes.LICENSE_CHECK_EXCEPTION; returnCode = LicenseCodes.LICENSE_CHECK_EXCEPTION;
} }
hasCode = true; hasCode = true;
} }
void validateLicense() { void validateLicense() {
try { try {
returnCode = _licenseLib.checkLicense( _keyword ); returnCode = _licenseLib.checkLicense( _keyword );
} }
catch (Throwable e) { catch (Throwable e) {
returnCode = LicenseCodes.LICENSE_CHECK_EXCEPTION; returnCode = LicenseCodes.LICENSE_CHECK_EXCEPTION;
//e.printStackTrace(); //e.printStackTrace();
} }
hasCode = true; hasCode = true;
} }
public volatile boolean hasCode = false; public volatile boolean hasCode = false;
public volatile int returnCode = -1; public volatile int returnCode = -1;
private String _keyword; private String _keyword;
private boolean _isTest; private boolean _isTest;
private LicenseAuthenticator _licenseLib; private LicenseAuthenticator _licenseLib;
} }

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="src" path="gen"/> <classpathentry kind="src" path="gen"/>
<classpathentry excluding="*.svn|.svn|com/mojang/minecraftpe/MainActivity.java|com/mojang/minecraftpe/Minecraft_Verizon.java" kind="src" path="src_linked"/> <classpathentry excluding="*.svn|.svn|com/mojang/minecraftpe/MainActivity.java|com/mojang/minecraftpe/Minecraft_Verizon.java" kind="src" path="src_linked"/>
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="output" path="bin/classes"/> <classpathentry kind="output" path="bin/classes"/>
</classpath> </classpath>

View File

@@ -1,40 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>MinecraftPocketEdition_java</name> <name>MinecraftPocketEdition_java</name>
<comment></comment> <comment></comment>
<projects> <projects>
</projects> </projects>
<buildSpec> <buildSpec>
<buildCommand> <buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name> <name>org.eclipse.jdt.core.javabuilder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name> <name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
</buildSpec> </buildSpec>
<natures> <natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature> <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature> <nature>org.eclipse.jdt.core.javanature</nature>
</natures> </natures>
<linkedResources> <linkedResources>
<link> <link>
<name>src_linked</name> <name>src_linked</name>
<type>2</type> <type>2</type>
<location>C:/dev/subversion/mojang/minecraftcpp/trunk/handheld/project/android/src</location> <location>C:/dev/subversion/mojang/minecraftcpp/trunk/handheld/project/android/src</location>
</link> </link>
</linkedResources> </linkedResources>
</projectDescription> </projectDescription>

View File

@@ -1,13 +1,13 @@
<!-- Verizon VCAST --> <!-- Verizon VCAST -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.START_BACKGROUND_SERVICE"/> <uses-permission android:name="android.permission.START_BACKGROUND_SERVICE"/>
<uses-permission android:name="com.verizon.vcast.apps.VCAST_APPS_LICENSE_SERVICE"/> <uses-permission android:name="com.verizon.vcast.apps.VCAST_APPS_LICENSE_SERVICE"/>
android:debuggable="true" android:debuggable="true"
<!-- Android MARKET --> <!-- Android MARKET -->
<uses-permission android:name="com.android.vending.CHECK_LICENSE" /> <uses-permission android:name="com.android.vending.CHECK_LICENSE" />
<!-- Google Analytics --> <!-- Google Analytics -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

File diff suppressed because it is too large Load Diff

View File

@@ -1,250 +1,250 @@
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := minecraftpe LOCAL_MODULE := minecraftpe
LOCAL_SRC_FILES := ../../../src/main.cpp \ LOCAL_SRC_FILES := ../../../src/main.cpp \
../../../src/main_android_java.cpp \ ../../../src/main_android_java.cpp \
../../../src/platform/input/Controller.cpp \ ../../../src/platform/input/Controller.cpp \
../../../src/platform/input/Keyboard.cpp \ ../../../src/platform/input/Keyboard.cpp \
../../../src/platform/input/Mouse.cpp \ ../../../src/platform/input/Mouse.cpp \
../../../src/platform/input/Multitouch.cpp \ ../../../src/platform/input/Multitouch.cpp \
../../../src/platform/time.cpp \ ../../../src/platform/time.cpp \
../../../src/platform/CThread.cpp \ ../../../src/platform/CThread.cpp \
../../../src/NinecraftApp.cpp \ ../../../src/NinecraftApp.cpp \
../../../src/Performance.cpp \ ../../../src/Performance.cpp \
../../../src/SharedConstants.cpp \ ../../../src/SharedConstants.cpp \
../../../src/client/IConfigListener.cpp \ ../../../src/client/IConfigListener.cpp \
../../../src/client/Minecraft.cpp \ ../../../src/client/Minecraft.cpp \
../../../src/client/MouseHandler.cpp \ ../../../src/client/MouseHandler.cpp \
../../../src/client/Options.cpp \ ../../../src/client/Options.cpp \
../../../src/client/OptionStrings.cpp \ ../../../src/client/OptionStrings.cpp \
../../../src/client/gamemode/GameMode.cpp \ ../../../src/client/gamemode/GameMode.cpp \
../../../src/client/gamemode/CreativeMode.cpp \ ../../../src/client/gamemode/CreativeMode.cpp \
../../../src/client/gamemode/SurvivalMode.cpp \ ../../../src/client/gamemode/SurvivalMode.cpp \
../../../src/client/gui/components/Button.cpp \ ../../../src/client/gui/components/Button.cpp \
../../../src/client/gui/components/ImageButton.cpp \ ../../../src/client/gui/components/ImageButton.cpp \
../../../src/client/gui/components/ItemPane.cpp \ ../../../src/client/gui/components/ItemPane.cpp \
../../../src/client/gui/components/InventoryPane.cpp \ ../../../src/client/gui/components/InventoryPane.cpp \
../../../src/client/gui/components/LargeImageButton.cpp \ ../../../src/client/gui/components/LargeImageButton.cpp \
../../../src/client/gui/components/RolledSelectionListH.cpp \ ../../../src/client/gui/components/RolledSelectionListH.cpp \
../../../src/client/gui/components/RolledSelectionListV.cpp \ ../../../src/client/gui/components/RolledSelectionListV.cpp \
../../../src/client/gui/components/ScrolledSelectionList.cpp \ ../../../src/client/gui/components/ScrolledSelectionList.cpp \
../../../src/client/gui/components/ScrollingPane.cpp \ ../../../src/client/gui/components/ScrollingPane.cpp \
../../../src/client/gui/components/SmallButton.cpp \ ../../../src/client/gui/components/SmallButton.cpp \
../../../src/client/gui/Font.cpp \ ../../../src/client/gui/Font.cpp \
../../../src/client/gui/Gui.cpp \ ../../../src/client/gui/Gui.cpp \
../../../src/client/gui/GuiComponent.cpp \ ../../../src/client/gui/GuiComponent.cpp \
../../../src/client/gui/Screen.cpp \ ../../../src/client/gui/Screen.cpp \
../../../src/client/gui/screens/ScreenChooser.cpp \ ../../../src/client/gui/screens/ScreenChooser.cpp \
../../../src/client/gui/screens/ChatScreen.cpp \ ../../../src/client/gui/screens/ChatScreen.cpp \
../../../src/client/gui/screens/ChestScreen.cpp \ ../../../src/client/gui/screens/ChestScreen.cpp \
../../../src/client/gui/screens/ConfirmScreen.cpp \ ../../../src/client/gui/screens/ConfirmScreen.cpp \
../../../src/client/gui/screens/DeathScreen.cpp \ ../../../src/client/gui/screens/DeathScreen.cpp \
../../../src/client/gui/screens/FurnaceScreen.cpp \ ../../../src/client/gui/screens/FurnaceScreen.cpp \
../../../src/client/gui/screens/InBedScreen.cpp \ ../../../src/client/gui/screens/InBedScreen.cpp \
../../../src/client/gui/screens/IngameBlockSelectionScreen.cpp \ ../../../src/client/gui/screens/IngameBlockSelectionScreen.cpp \
../../../src/client/gui/screens/JoinGameScreen.cpp \ ../../../src/client/gui/screens/JoinGameScreen.cpp \
../../../src/client/gui/screens/OptionsScreen.cpp \ ../../../src/client/gui/screens/OptionsScreen.cpp \
../../../src/client/gui/screens/PauseScreen.cpp \ ../../../src/client/gui/screens/PauseScreen.cpp \
../../../src/client/gui/screens/ProgressScreen.cpp \ ../../../src/client/gui/screens/ProgressScreen.cpp \
../../../src/client/gui/screens/RenameMPLevelScreen.cpp \ ../../../src/client/gui/screens/RenameMPLevelScreen.cpp \
../../../src/client/gui/screens/SelectWorldScreen.cpp \ ../../../src/client/gui/screens/SelectWorldScreen.cpp \
../../../src/client/gui/screens/StartMenuScreen.cpp \ ../../../src/client/gui/screens/StartMenuScreen.cpp \
../../../src/client/gui/screens/TextEditScreen.cpp \ ../../../src/client/gui/screens/TextEditScreen.cpp \
../../../src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp \ ../../../src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp \
../../../src/client/gui/screens/touch/TouchJoinGameScreen.cpp \ ../../../src/client/gui/screens/touch/TouchJoinGameScreen.cpp \
../../../src/client/gui/screens/touch/TouchSelectWorldScreen.cpp \ ../../../src/client/gui/screens/touch/TouchSelectWorldScreen.cpp \
../../../src/client/gui/screens/touch/TouchStartMenuScreen.cpp \ ../../../src/client/gui/screens/touch/TouchStartMenuScreen.cpp \
../../../src/client/gui/screens/UploadPhotoScreen.cpp \ ../../../src/client/gui/screens/UploadPhotoScreen.cpp \
../../../src/client/gui/screens/crafting/PaneCraftingScreen.cpp \ ../../../src/client/gui/screens/crafting/PaneCraftingScreen.cpp \
../../../src/client/gui/screens/crafting/WorkbenchScreen.cpp \ ../../../src/client/gui/screens/crafting/WorkbenchScreen.cpp \
../../../src/client/model/ChickenModel.cpp \ ../../../src/client/model/ChickenModel.cpp \
../../../src/client/model/CowModel.cpp \ ../../../src/client/model/CowModel.cpp \
../../../src/client/model/HumanoidModel.cpp \ ../../../src/client/model/HumanoidModel.cpp \
../../../src/client/model/PigModel.cpp \ ../../../src/client/model/PigModel.cpp \
../../../src/client/model/SheepFurModel.cpp \ ../../../src/client/model/SheepFurModel.cpp \
../../../src/client/model/SheepModel.cpp \ ../../../src/client/model/SheepModel.cpp \
../../../src/client/model/QuadrupedModel.cpp \ ../../../src/client/model/QuadrupedModel.cpp \
../../../src/client/model/geom/Cube.cpp \ ../../../src/client/model/geom/Cube.cpp \
../../../src/client/model/geom/ModelPart.cpp \ ../../../src/client/model/geom/ModelPart.cpp \
../../../src/client/model/geom/Polygon.cpp \ ../../../src/client/model/geom/Polygon.cpp \
../../../src/client/particle/Particle.cpp \ ../../../src/client/particle/Particle.cpp \
../../../src/client/particle/ParticleEngine.cpp \ ../../../src/client/particle/ParticleEngine.cpp \
../../../src/client/player/LocalPlayer.cpp \ ../../../src/client/player/LocalPlayer.cpp \
../../../src/client/player/RemotePlayer.cpp \ ../../../src/client/player/RemotePlayer.cpp \
../../../src/client/player/input/KeyboardInput.cpp \ ../../../src/client/player/input/KeyboardInput.cpp \
../../../src/client/player/input/touchscreen/TouchscreenInput.cpp \ ../../../src/client/player/input/touchscreen/TouchscreenInput.cpp \
../../../src/client/renderer/Chunk.cpp \ ../../../src/client/renderer/Chunk.cpp \
../../../src/client/renderer/EntityTileRenderer.cpp \ ../../../src/client/renderer/EntityTileRenderer.cpp \
../../../src/client/renderer/GameRenderer.cpp \ ../../../src/client/renderer/GameRenderer.cpp \
../../../src/client/renderer/ItemInHandRenderer.cpp \ ../../../src/client/renderer/ItemInHandRenderer.cpp \
../../../src/client/renderer/LevelRenderer.cpp \ ../../../src/client/renderer/LevelRenderer.cpp \
../../../src/client/renderer/RenderChunk.cpp \ ../../../src/client/renderer/RenderChunk.cpp \
../../../src/client/renderer/RenderList.cpp \ ../../../src/client/renderer/RenderList.cpp \
../../../src/client/renderer/Tesselator.cpp \ ../../../src/client/renderer/Tesselator.cpp \
../../../src/client/renderer/Textures.cpp \ ../../../src/client/renderer/Textures.cpp \
../../../src/client/renderer/TileRenderer.cpp \ ../../../src/client/renderer/TileRenderer.cpp \
../../../src/client/renderer/gles.cpp \ ../../../src/client/renderer/gles.cpp \
../../../src/client/renderer/culling/Frustum.cpp \ ../../../src/client/renderer/culling/Frustum.cpp \
../../../src/client/renderer/entity/ArrowRenderer.cpp \ ../../../src/client/renderer/entity/ArrowRenderer.cpp \
../../../src/client/renderer/entity/ChickenRenderer.cpp \ ../../../src/client/renderer/entity/ChickenRenderer.cpp \
../../../src/client/renderer/entity/EntityRenderDispatcher.cpp \ ../../../src/client/renderer/entity/EntityRenderDispatcher.cpp \
../../../src/client/renderer/entity/EntityRenderer.cpp \ ../../../src/client/renderer/entity/EntityRenderer.cpp \
../../../src/client/renderer/entity/HumanoidMobRenderer.cpp \ ../../../src/client/renderer/entity/HumanoidMobRenderer.cpp \
../../../src/client/renderer/entity/ItemRenderer.cpp \ ../../../src/client/renderer/entity/ItemRenderer.cpp \
../../../src/client/renderer/entity/ItemSpriteRenderer.cpp \ ../../../src/client/renderer/entity/ItemSpriteRenderer.cpp \
../../../src/client/renderer/entity/MobRenderer.cpp \ ../../../src/client/renderer/entity/MobRenderer.cpp \
../../../src/client/renderer/entity/PaintingRenderer.cpp \ ../../../src/client/renderer/entity/PaintingRenderer.cpp \
../../../src/client/renderer/entity/PlayerRenderer.cpp \ ../../../src/client/renderer/entity/PlayerRenderer.cpp \
../../../src/client/renderer/entity/SheepRenderer.cpp \ ../../../src/client/renderer/entity/SheepRenderer.cpp \
../../../src/client/renderer/entity/TntRenderer.cpp \ ../../../src/client/renderer/entity/TntRenderer.cpp \
../../../src/client/renderer/entity/TripodCameraRenderer.cpp \ ../../../src/client/renderer/entity/TripodCameraRenderer.cpp \
../../../src/client/renderer/ptexture/DynamicTexture.cpp \ ../../../src/client/renderer/ptexture/DynamicTexture.cpp \
../../../src/client/renderer/tileentity/ChestRenderer.cpp \ ../../../src/client/renderer/tileentity/ChestRenderer.cpp \
../../../src/client/renderer/tileentity/SignRenderer.cpp \ ../../../src/client/renderer/tileentity/SignRenderer.cpp \
../../../src/client/renderer/tileentity/TileEntityRenderDispatcher.cpp \ ../../../src/client/renderer/tileentity/TileEntityRenderDispatcher.cpp \
../../../src/client/renderer/tileentity/TileEntityRenderer.cpp \ ../../../src/client/renderer/tileentity/TileEntityRenderer.cpp \
../../../src/client/sound/Sound.cpp \ ../../../src/client/sound/Sound.cpp \
../../../src/client/sound/SoundEngine.cpp \ ../../../src/client/sound/SoundEngine.cpp \
../../../src/locale/I18n.cpp \ ../../../src/locale/I18n.cpp \
../../../src/nbt/Tag.cpp \ ../../../src/nbt/Tag.cpp \
../../../src/network/command/CommandServer.cpp \ ../../../src/network/command/CommandServer.cpp \
../../../src/network/ClientSideNetworkHandler.cpp \ ../../../src/network/ClientSideNetworkHandler.cpp \
../../../src/network/NetEventCallback.cpp \ ../../../src/network/NetEventCallback.cpp \
../../../src/network/Packet.cpp \ ../../../src/network/Packet.cpp \
../../../src/network/RakNetInstance.cpp \ ../../../src/network/RakNetInstance.cpp \
../../../src/network/ServerSideNetworkHandler.cpp \ ../../../src/network/ServerSideNetworkHandler.cpp \
../../../src/server/ServerLevel.cpp \ ../../../src/server/ServerLevel.cpp \
../../../src/server/ServerPlayer.cpp \ ../../../src/server/ServerPlayer.cpp \
../../../src/util/DataIO.cpp \ ../../../src/util/DataIO.cpp \
../../../src/util/Mth.cpp \ ../../../src/util/Mth.cpp \
../../../src/util/StringUtils.cpp \ ../../../src/util/StringUtils.cpp \
../../../src/util/PerfTimer.cpp \ ../../../src/util/PerfTimer.cpp \
../../../src/util/PerfRenderer.cpp \ ../../../src/util/PerfRenderer.cpp \
../../../src/world/Direction.cpp \ ../../../src/world/Direction.cpp \
../../../src/world/entity/AgableMob.cpp \ ../../../src/world/entity/AgableMob.cpp \
../../../src/world/entity/Entity.cpp \ ../../../src/world/entity/Entity.cpp \
../../../src/world/entity/EntityFactory.cpp \ ../../../src/world/entity/EntityFactory.cpp \
../../../src/world/entity/FlyingMob.cpp \ ../../../src/world/entity/FlyingMob.cpp \
../../../src/world/entity/HangingEntity.cpp \ ../../../src/world/entity/HangingEntity.cpp \
../../../src/world/entity/Mob.cpp \ ../../../src/world/entity/Mob.cpp \
../../../src/world/entity/MobCategory.cpp \ ../../../src/world/entity/MobCategory.cpp \
../../../src/world/entity/Motive.cpp \ ../../../src/world/entity/Motive.cpp \
../../../src/world/entity/Painting.cpp \ ../../../src/world/entity/Painting.cpp \
../../../src/world/entity/PathfinderMob.cpp \ ../../../src/world/entity/PathfinderMob.cpp \
../../../src/world/entity/SynchedEntityData.cpp \ ../../../src/world/entity/SynchedEntityData.cpp \
../../../src/world/entity/ai/control/MoveControl.cpp \ ../../../src/world/entity/ai/control/MoveControl.cpp \
../../../src/world/entity/animal/Animal.cpp \ ../../../src/world/entity/animal/Animal.cpp \
../../../src/world/entity/animal/Chicken.cpp \ ../../../src/world/entity/animal/Chicken.cpp \
../../../src/world/entity/animal/Cow.cpp \ ../../../src/world/entity/animal/Cow.cpp \
../../../src/world/entity/animal/Pig.cpp \ ../../../src/world/entity/animal/Pig.cpp \
../../../src/world/entity/animal/Sheep.cpp \ ../../../src/world/entity/animal/Sheep.cpp \
../../../src/world/entity/animal/WaterAnimal.cpp \ ../../../src/world/entity/animal/WaterAnimal.cpp \
../../../src/world/entity/item/FallingTile.cpp \ ../../../src/world/entity/item/FallingTile.cpp \
../../../src/world/entity/item/ItemEntity.cpp \ ../../../src/world/entity/item/ItemEntity.cpp \
../../../src/world/entity/item/PrimedTnt.cpp \ ../../../src/world/entity/item/PrimedTnt.cpp \
../../../src/world/entity/item/TripodCamera.cpp \ ../../../src/world/entity/item/TripodCamera.cpp \
../../../src/world/entity/monster/Creeper.cpp \ ../../../src/world/entity/monster/Creeper.cpp \
../../../src/world/entity/monster/Monster.cpp \ ../../../src/world/entity/monster/Monster.cpp \
../../../src/world/entity/monster/PigZombie.cpp \ ../../../src/world/entity/monster/PigZombie.cpp \
../../../src/world/entity/monster/Skeleton.cpp \ ../../../src/world/entity/monster/Skeleton.cpp \
../../../src/world/entity/monster/Spider.cpp \ ../../../src/world/entity/monster/Spider.cpp \
../../../src/world/entity/monster/Zombie.cpp \ ../../../src/world/entity/monster/Zombie.cpp \
../../../src/world/entity/projectile/Arrow.cpp \ ../../../src/world/entity/projectile/Arrow.cpp \
../../../src/world/entity/projectile/Throwable.cpp \ ../../../src/world/entity/projectile/Throwable.cpp \
../../../src/world/entity/player/Inventory.cpp \ ../../../src/world/entity/player/Inventory.cpp \
../../../src/world/entity/player/Player.cpp \ ../../../src/world/entity/player/Player.cpp \
../../../src/world/food/SimpleFoodData.cpp \ ../../../src/world/food/SimpleFoodData.cpp \
../../../src/world/inventory/BaseContainerMenu.cpp \ ../../../src/world/inventory/BaseContainerMenu.cpp \
../../../src/world/inventory/ContainerMenu.cpp \ ../../../src/world/inventory/ContainerMenu.cpp \
../../../src/world/inventory/FillingContainer.cpp \ ../../../src/world/inventory/FillingContainer.cpp \
../../../src/world/inventory/FurnaceMenu.cpp \ ../../../src/world/inventory/FurnaceMenu.cpp \
../../../src/world/item/BedItem.cpp \ ../../../src/world/item/BedItem.cpp \
../../../src/world/item/DyePowderItem.cpp \ ../../../src/world/item/DyePowderItem.cpp \
../../../src/world/item/Item.cpp \ ../../../src/world/item/Item.cpp \
../../../src/world/item/ItemInstance.cpp \ ../../../src/world/item/ItemInstance.cpp \
../../../src/world/item/HangingEntityItem.cpp \ ../../../src/world/item/HangingEntityItem.cpp \
../../../src/world/item/HatchetItem.cpp \ ../../../src/world/item/HatchetItem.cpp \
../../../src/world/item/HoeItem.cpp \ ../../../src/world/item/HoeItem.cpp \
../../../src/world/item/PickaxeItem.cpp \ ../../../src/world/item/PickaxeItem.cpp \
../../../src/world/item/ShovelItem.cpp \ ../../../src/world/item/ShovelItem.cpp \
../../../src/world/item/crafting/Recipe.cpp \ ../../../src/world/item/crafting/Recipe.cpp \
../../../src/world/item/crafting/Recipes.cpp \ ../../../src/world/item/crafting/Recipes.cpp \
../../../src/world/item/crafting/FurnaceRecipes.cpp \ ../../../src/world/item/crafting/FurnaceRecipes.cpp \
../../../src/world/item/crafting/OreRecipes.cpp \ ../../../src/world/item/crafting/OreRecipes.cpp \
../../../src/world/item/crafting/StructureRecipes.cpp \ ../../../src/world/item/crafting/StructureRecipes.cpp \
../../../src/world/item/crafting/ToolRecipes.cpp \ ../../../src/world/item/crafting/ToolRecipes.cpp \
../../../src/world/item/crafting/WeaponRecipes.cpp \ ../../../src/world/item/crafting/WeaponRecipes.cpp \
../../../src/world/level/Explosion.cpp \ ../../../src/world/level/Explosion.cpp \
../../../src/world/level/Level.cpp \ ../../../src/world/level/Level.cpp \
../../../src/world/level/LightLayer.cpp \ ../../../src/world/level/LightLayer.cpp \
../../../src/world/level/LightUpdate.cpp \ ../../../src/world/level/LightUpdate.cpp \
../../../src/world/level/MobSpawner.cpp \ ../../../src/world/level/MobSpawner.cpp \
../../../src/world/level/Region.cpp \ ../../../src/world/level/Region.cpp \
../../../src/world/level/TickNextTickData.cpp \ ../../../src/world/level/TickNextTickData.cpp \
../../../src/world/level/biome/Biome.cpp \ ../../../src/world/level/biome/Biome.cpp \
../../../src/world/level/biome/BiomeSource.cpp \ ../../../src/world/level/biome/BiomeSource.cpp \
../../../src/world/level/chunk/LevelChunk.cpp \ ../../../src/world/level/chunk/LevelChunk.cpp \
../../../src/world/level/dimension/Dimension.cpp \ ../../../src/world/level/dimension/Dimension.cpp \
../../../src/world/level/levelgen/CanyonFeature.cpp \ ../../../src/world/level/levelgen/CanyonFeature.cpp \
../../../src/world/level/levelgen/DungeonFeature.cpp \ ../../../src/world/level/levelgen/DungeonFeature.cpp \
../../../src/world/level/levelgen/LargeCaveFeature.cpp \ ../../../src/world/level/levelgen/LargeCaveFeature.cpp \
../../../src/world/level/levelgen/LargeFeature.cpp \ ../../../src/world/level/levelgen/LargeFeature.cpp \
../../../src/world/level/levelgen/RandomLevelSource.cpp \ ../../../src/world/level/levelgen/RandomLevelSource.cpp \
../../../src/world/level/levelgen/feature/Feature.cpp \ ../../../src/world/level/levelgen/feature/Feature.cpp \
../../../src/world/level/levelgen/synth/ImprovedNoise.cpp \ ../../../src/world/level/levelgen/synth/ImprovedNoise.cpp \
../../../src/world/level/levelgen/synth/PerlinNoise.cpp \ ../../../src/world/level/levelgen/synth/PerlinNoise.cpp \
../../../src/world/level/levelgen/synth/Synth.cpp \ ../../../src/world/level/levelgen/synth/Synth.cpp \
../../../src/world/level/material/Material.cpp \ ../../../src/world/level/material/Material.cpp \
../../../src/world/level/pathfinder/Path.cpp \ ../../../src/world/level/pathfinder/Path.cpp \
../../../src/world/level/storage/ExternalFileLevelStorage.cpp \ ../../../src/world/level/storage/ExternalFileLevelStorage.cpp \
../../../src/world/level/storage/ExternalFileLevelStorageSource.cpp \ ../../../src/world/level/storage/ExternalFileLevelStorageSource.cpp \
../../../src/world/level/storage/FolderMethods.cpp \ ../../../src/world/level/storage/FolderMethods.cpp \
../../../src/world/level/storage/LevelData.cpp \ ../../../src/world/level/storage/LevelData.cpp \
../../../src/world/level/storage/LevelStorageSource.cpp \ ../../../src/world/level/storage/LevelStorageSource.cpp \
../../../src/world/level/storage/RegionFile.cpp \ ../../../src/world/level/storage/RegionFile.cpp \
../../../src/world/level/tile/BedTile.cpp \ ../../../src/world/level/tile/BedTile.cpp \
../../../src/world/level/tile/ChestTile.cpp \ ../../../src/world/level/tile/ChestTile.cpp \
../../../src/world/level/tile/CropTile.cpp \ ../../../src/world/level/tile/CropTile.cpp \
../../../src/world/level/tile/DoorTile.cpp \ ../../../src/world/level/tile/DoorTile.cpp \
../../../src/world/level/tile/EntityTile.cpp \ ../../../src/world/level/tile/EntityTile.cpp \
../../../src/world/level/tile/FurnaceTile.cpp \ ../../../src/world/level/tile/FurnaceTile.cpp \
../../../src/world/level/tile/GrassTile.cpp \ ../../../src/world/level/tile/GrassTile.cpp \
../../../src/world/level/tile/LightGemTile.cpp \ ../../../src/world/level/tile/LightGemTile.cpp \
../../../src/world/level/tile/MelonTile.cpp \ ../../../src/world/level/tile/MelonTile.cpp \
../../../src/world/level/tile/Mushroom.cpp \ ../../../src/world/level/tile/Mushroom.cpp \
../../../src/world/level/tile/NetherReactor.cpp \ ../../../src/world/level/tile/NetherReactor.cpp \
../../../src/world/level/tile/NetherReactorPattern.cpp \ ../../../src/world/level/tile/NetherReactorPattern.cpp \
../../../src/world/level/tile/SandTile.cpp \ ../../../src/world/level/tile/SandTile.cpp \
../../../src/world/level/tile/StemTile.cpp \ ../../../src/world/level/tile/StemTile.cpp \
../../../src/world/level/tile/StoneSlabTile.cpp \ ../../../src/world/level/tile/StoneSlabTile.cpp \
../../../src/world/level/tile/TallGrass.cpp \ ../../../src/world/level/tile/TallGrass.cpp \
../../../src/world/level/tile/Tile.cpp \ ../../../src/world/level/tile/Tile.cpp \
../../../src/world/level/tile/TrapDoorTile.cpp \ ../../../src/world/level/tile/TrapDoorTile.cpp \
../../../src/world/level/tile/entity/ChestTileEntity.cpp \ ../../../src/world/level/tile/entity/ChestTileEntity.cpp \
../../../src/world/level/tile/entity/NetherReactorTileEntity.cpp \ ../../../src/world/level/tile/entity/NetherReactorTileEntity.cpp \
../../../src/world/level/tile/entity/SignTileEntity.cpp \ ../../../src/world/level/tile/entity/SignTileEntity.cpp \
../../../src/world/level/tile/entity/TileEntity.cpp \ ../../../src/world/level/tile/entity/TileEntity.cpp \
../../../src/world/level/tile/entity/FurnaceTileEntity.cpp \ ../../../src/world/level/tile/entity/FurnaceTileEntity.cpp \
../../../src/world/phys/HitResult.cpp ../../../src/world/phys/HitResult.cpp
LOCAL_CFLAGS := -Wno-psabi $(LOCAL_CFLAGS) LOCAL_CFLAGS := -Wno-psabi $(LOCAL_CFLAGS)
LOCAL_CFLAGS := -DPRE_ANDROID23 -DANDROID_PUBLISH $(LOCAL_CFLAGS) LOCAL_CFLAGS := -DPRE_ANDROID23 -DANDROID_PUBLISH $(LOCAL_CFLAGS)
#LOCAL_CFLAGS := -DPRE_ANDROID23 -DANDROID_PUBLISH -DDEMO_MODE $(LOCAL_CFLAGS) #LOCAL_CFLAGS := -DPRE_ANDROID23 -DANDROID_PUBLISH -DDEMO_MODE $(LOCAL_CFLAGS)
#LOCAL_CFLAGS := -DPRE_ANDROID23 -DDEMO_MODE $(LOCAL_CFLAGS) #LOCAL_CFLAGS := -DPRE_ANDROID23 -DDEMO_MODE $(LOCAL_CFLAGS)
#LOCAL_CFLAGS := -DPRE_ANDROID23 $(LOCAL_CFLAGS) #LOCAL_CFLAGS := -DPRE_ANDROID23 $(LOCAL_CFLAGS)
LOCAL_LDLIBS := -llog -lEGL -lGLESv1_CM LOCAL_LDLIBS := -llog -lEGL -lGLESv1_CM
LOCAL_STATIC_LIBRARIES := RakNet LOCAL_STATIC_LIBRARIES := RakNet
TARGET_ARCH_ABI := armeabi-v7a TARGET_ARCH_ABI := armeabi-v7a
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)
# NOTE: environment var NDK_MODULE_PATH needs to point to lib_projects folder # NOTE: environment var NDK_MODULE_PATH needs to point to lib_projects folder
$(call import-module, raknet/jni) $(call import-module, raknet/jni)

View File

@@ -1,66 +1,66 @@
-optimizationpasses 5 -optimizationpasses 5
-dontusemixedcaseclassnames -dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclasses
-dontpreverify -dontpreverify
-verbose -verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class com.mojang.minecraftpe.GameModeButton -keep public class com.mojang.minecraftpe.GameModeButton
-keep public class com.mojang.android.StringValue -keep public class com.mojang.android.StringValue
-keep public class * extends android.app.Activity -keep public class * extends android.app.Activity
-keep public class * extends com.mojang.minecraftpe.MainActivity -keep public class * extends com.mojang.minecraftpe.MainActivity
-keep public class * extends MainActivity -keep public class * extends MainActivity
-keep public class * extends android.app.Application -keep public class * extends android.app.Application
-keep public class * extends android.app.Service -keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider -keep public class * extends android.content.ContentProvider
-keep public class com.android.vending.licensing.ILicensingService -keep public class com.android.vending.licensing.ILicensingService
-keep,allowobfuscation class com.mojang.** { *** *(...); } -keep,allowobfuscation class com.mojang.** { *** *(...); }
-keepclasseswithmembernames class * { -keepclasseswithmembernames class * {
native <methods>; native <methods>;
} }
-keepclasseswithmembernames class * { -keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet); public <init>(android.content.Context, android.util.AttributeSet);
} }
-keepclasseswithmembernames class * { -keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int); public <init>(android.content.Context, android.util.AttributeSet, int);
} }
-keepclassmembers enum * { -keepclassmembers enum * {
public static **[] values(); public static **[] values();
public static ** valueOf(java.lang.String); public static ** valueOf(java.lang.String);
} }
-keepclassmembers class * extends android.app.Activity { -keepclassmembers class * extends android.app.Activity {
static public void saveScreenshot(java.lang.String, int, int, int[]); static public void saveScreenshot(java.lang.String, int, int, int[]);
public int[] getImageData(java.lang.String); public int[] getImageData(java.lang.String);
public byte[] getFileDataBytes(java.lang.String); public byte[] getFileDataBytes(java.lang.String);
public java.lang.String getPlatformStringVar(int); public java.lang.String getPlatformStringVar(int);
public int getScreenWidth(); public int getScreenWidth();
public int getScreenHeight(); public int getScreenHeight();
public float getPixelsPerMillimeter(); public float getPixelsPerMillimeter();
public int checkLicense(); public int checkLicense();
public boolean isNetworkEnabled(boolean); public boolean isNetworkEnabled(boolean);
public java.lang.String getDateString(int); public java.lang.String getDateString(int);
public boolean hasBuyButtonWhenInvalidLicense(); public boolean hasBuyButtonWhenInvalidLicense();
public void postScreenshotToFacebook(java.lang.String, int, int, int[]); public void postScreenshotToFacebook(java.lang.String, int, int, int[]);
public void quit(); public void quit();
public void displayDialog(int); public void displayDialog(int);
public void tick(); public void tick();
public java.lang.String[] getOptionStrings(); public java.lang.String[] getOptionStrings();
public void buyGame(); public void buyGame();
public void playSound(java.lang.String, float, float); public void playSound(java.lang.String, float, float);
public boolean isTouchscreen(); public boolean isTouchscreen();
public void setIsPowerVR(boolean); public void setIsPowerVR(boolean);
public void initiateUserInput(int); public void initiateUserInput(int);
public int getUserInputStatus(); public int getUserInputStatus();
public java.lang.String[] getUserInputString(); public java.lang.String[] getUserInputString();
public void vibrate(int); public void vibrate(int);
} }
-keep class * implements android.os.Parcelable { -keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *; public static final android.os.Parcelable$Creator *;
} }

View File

@@ -1,4 +1,4 @@
<bitmap xmlns:android="http://schemas.android.com/apk/res/android" <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/bg32" android:src="@drawable/bg32"
android:tileMode="repeat" android:tileMode="repeat"
android:dither="false" /> android:dither="false" />

View File

@@ -1,5 +1,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" <item android:state_pressed="true"
android:drawable="@drawable/cancel_1_3" /> android:drawable="@drawable/cancel_1_3" />
<item android:drawable="@drawable/cancel_0_3" /> <item android:drawable="@drawable/cancel_0_3" />
</selector> </selector>

View File

@@ -1,5 +1,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" <item android:state_pressed="true"
android:drawable="@drawable/create_1_3" /> android:drawable="@drawable/create_1_3" />
<item android:drawable="@drawable/create_0_3" /> <item android:drawable="@drawable/create_0_3" />
</selector> </selector>

View File

@@ -1,5 +1,5 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" <item android:state_checked="true"
android:drawable="@drawable/creative_3" /> android:drawable="@drawable/creative_3" />
<item android:drawable="@drawable/survival_3" /> <item android:drawable="@drawable/survival_3" />
</selector> </selector>

View File

@@ -1,177 +1,177 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical" android:background="@drawable/bgtiled"> android:orientation="vertical" android:background="@drawable/bgtiled">
<LinearLayout <LinearLayout
android:id="@+id/linearLayout2" android:id="@+id/linearLayout2"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="18" android:layout_weight="18"
android:orientation="vertical" > android:orientation="vertical" >
<LinearLayout <LinearLayout
android:id="@+id/linearLayout1" android:id="@+id/linearLayout1"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_weight="0" > android:layout_weight="0" >
<ImageButton <ImageButton
android:id="@+id/button_createworld_cancel" android:id="@+id/button_createworld_cancel"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:layout_weight="3" android:layout_weight="3"
android:background="@drawable/btn_nw_cancel" /> android:background="@drawable/btn_nw_cancel" />
<ImageButton <ImageButton
android:id="@+id/header_createworld_worldname" android:id="@+id/header_createworld_worldname"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:layout_weight="7" android:layout_weight="7"
android:background="@drawable/worldname_3" /> android:background="@drawable/worldname_3" />
<ImageButton <ImageButton
android:id="@+id/button_createworld_create" android:id="@+id/button_createworld_create"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:layout_weight="3" android:layout_weight="3"
android:background="@drawable/btn_nw_create" /> android:background="@drawable/btn_nw_create" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/linearLayout3" android:id="@+id/linearLayout3"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_horizontal" android:layout_marginBottom="20dp"> android:gravity="center_horizontal" android:layout_marginBottom="20dp">
<View <View
android:id="@+id/View01" android:id="@+id/View01"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:layout_weight="0.25" /> android:layout_weight="0.25" />
<com.mojang.android.EditTextAscii <com.mojang.android.EditTextAscii
android:id="@+id/editText_worldName" android:id="@+id/editText_worldName"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0.50" android:layout_weight="0.50"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:text="@string/createworld_new_world" android:text="@string/createworld_new_world"
android:typeface="monospace" > android:typeface="monospace" >
<requestFocus /> <requestFocus />
</com.mojang.android.EditTextAscii> </com.mojang.android.EditTextAscii>
<View <View
android:id="@+id/view1" android:id="@+id/view1"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:layout_weight="0.25" /> android:layout_weight="0.25" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/linearLayout4" android:id="@+id/linearLayout4"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="50dp" android:layout_height="50dp"
android:gravity="center_horizontal"> android:gravity="center_horizontal">
<com.mojang.minecraftpe.GameModeButton <com.mojang.minecraftpe.GameModeButton
android:id="@+id/button_gameMode" android:id="@+id/button_gameMode"
android:layout_width="173dp" android:layout_width="173dp"
android:layout_height="46dp" android:layout_height="46dp"
android:background="@drawable/btngamemode" android:background="@drawable/btngamemode"
android:text="Button" android:textOff=" " android:textOn=" "/> android:text="Button" android:textOff=" " android:textOn=" "/>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/linearLayout5" android:id="@+id/linearLayout5"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:paddingBottom="20dp" > android:paddingBottom="20dp" >
<TextView <TextView
android:id="@+id/labelGameModeDesc" android:id="@+id/labelGameModeDesc"
android:text="@string/gamemode_survival_summary" android:text="@string/gamemode_survival_summary"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:typeface="monospace"/> android:typeface="monospace"/>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/linearLayout6" android:id="@+id/linearLayout6"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_horizontal" > android:gravity="center_horizontal" >
<TextView <TextView
android:id="@+id/textView2" android:id="@+id/textView2"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/createworld_seed" android:typeface="monospace"/> android:text="@string/createworld_seed" android:typeface="monospace"/>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/linearLayout7" android:id="@+id/linearLayout7"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:orientation="horizontal" > android:orientation="horizontal" >
<View <View
android:id="@+id/View03" android:id="@+id/View03"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:layout_weight="0.25" /> android:layout_weight="0.25" />
<EditText <EditText
android:id="@+id/editText_worldSeed" android:id="@+id/editText_worldSeed"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0.5" android:layout_weight="0.5"
android:singleLine="true" android:singleLine="true"
android:typeface="monospace" android:gravity="center_horizontal"/> android:typeface="monospace" android:gravity="center_horizontal"/>
<View <View
android:id="@+id/View02" android:id="@+id/View02"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:layout_weight="0.25" /> android:layout_weight="0.25" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/linearLayout8" android:id="@+id/linearLayout8"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:orientation="horizontal" > android:orientation="horizontal" >
<TextView <TextView
android:id="@+id/textView3" android:id="@+id/textView3"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/createworld_seed_info" android:typeface="monospace"/> android:text="@string/createworld_seed_info" android:typeface="monospace"/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:background="@drawable/bgtiled" android:background="@drawable/bgtiled"
android:tileMode="repeat" > android:tileMode="repeat" >
<TextView android:text="Multiplayer username" <TextView android:text="Multiplayer username"
android:layout_width="540px" android:layout_width="540px"
android:layout_height="24dp" /> android:layout_height="24dp" />
<EditText android:id="@+id/editText_options_mpusername" <EditText android:id="@+id/editText_options_mpusername"
android:text="" android:text=""
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:singleLine="true"> android:singleLine="true">
</EditText> </EditText>
</LinearLayout> </LinearLayout>

View File

@@ -1,28 +1,28 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/bgtiled" android:background="@drawable/bgtiled"
android:tileMode="repeat" android:tileMode="repeat"
android:gravity="center_horizontal" android:gravity="center_horizontal"
> >
<TextView android:text = "@string/renameworld_title" <TextView android:text = "@string/renameworld_title"
android:layout_width="360dp" android:layout_width="360dp"
android:layout_height="24dp" android:layout_height="24dp"
android:typeface="monospace" android:typeface="monospace"
/> />
<com.mojang.android.EditTextAscii <com.mojang.android.EditTextAscii
android:id="@+id/editText_worldNameRename" android:id="@+id/editText_worldNameRename"
android:text="@string/renameworld_saved_world" android:text="@string/renameworld_saved_world"
android:layout_width="360dp" android:layout_width="360dp"
android:layout_height="48dp" android:layout_height="48dp"
android:singleLine="true" android:singleLine="true"
android:typeface="monospace" android:typeface="monospace"
android:maxLength="64" android:maxLength="64"
android:imeActionLabel="Ok" android:imeActionLabel="Ok"
android:imeOptions="actionDone" /> android:imeOptions="actionDone" />
<View <View
android:layout_width="360dp" android:layout_width="360dp"
android:layout_height="10px" /> android:layout_height="10px" />
</LinearLayout> </LinearLayout>

View File

@@ -1,40 +1,40 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">Minecraft - Pocket Edition</string> <string name="app_name">Minecraft - Pocket Edition</string>
<string name="app_name_demo">Minecraft - Pocket Edition Demo</string> <string name="app_name_demo">Minecraft - Pocket Edition Demo</string>
<string name="xperiaplayoptimized_content">true</string> <string name="xperiaplayoptimized_content">true</string>
<string name="app_name_short">Minecraft PE</string> <string name="app_name_short">Minecraft PE</string>
<string name="app_name_short_demo">Minecraft PE Demo</string> <string name="app_name_short_demo">Minecraft PE Demo</string>
<!-- CREATE NEW WORLD --> <!-- CREATE NEW WORLD -->
<string name="createworld_name">World name</string> <string name="createworld_name">World name</string>
<string name="createworld_new_world">Unnamed world</string> <string name="createworld_new_world">Unnamed world</string>
<string name="createworld_seed">Seed for the World Generator</string> <string name="createworld_seed">Seed for the World Generator</string>
<string name="createworld_seed_info">Leave blank for random seed</string> <string name="createworld_seed_info">Leave blank for random seed</string>
<string name="gamemode_survival_summary">Mobs, health and gather resources</string> <string name="gamemode_survival_summary">Mobs, health and gather resources</string>
<string name="gamemode_creative_summary">Unlimited resources and flying</string> <string name="gamemode_creative_summary">Unlimited resources and flying</string>
<!-- RENAME WORLD --> <!-- RENAME WORLD -->
<string name="renameworld_title">Save world as</string> <string name="renameworld_title">Save world as</string>
<string name="renameworld_saved_world">Saved World</string> <string name="renameworld_saved_world">Saved World</string>
<!-- MAIN MENU OPTIONS --> <!-- MAIN MENU OPTIONS -->
<string name="mmoptions_mp_username_title">Username</string> <string name="mmoptions_mp_username_title">Username</string>
<string name="mmoptions_mp_username_dialog">Enter your username</string> <string name="mmoptions_mp_username_dialog">Enter your username</string>
<string name="mmoptions_mp_server_visible_default_title">Server visible by default</string> <string name="mmoptions_mp_server_visible_default_title">Server visible by default</string>
<string name="mmoptions_ctrl_sensitivity_title">Sensitivity</string> <string name="mmoptions_ctrl_sensitivity_title">Sensitivity</string>
<string name="mmoptions_ctrl_invertmouse_title">Invert Y-axis</string> <string name="mmoptions_ctrl_invertmouse_title">Invert Y-axis</string>
<string name="mmoptions_ctrl_islefthanded_title">Lefty</string> <string name="mmoptions_ctrl_islefthanded_title">Lefty</string>
<string name="mmoptions_ctrl_usetouchscreen_title">Use touch screen</string> <string name="mmoptions_ctrl_usetouchscreen_title">Use touch screen</string>
<string name="mmoptions_ctrl_usetouchjoypad_title">Split touch controls</string> <string name="mmoptions_ctrl_usetouchjoypad_title">Split touch controls</string>
<string name="mmoptions_feedback_vibration_title">Vibration</string> <string name="mmoptions_feedback_vibration_title">Vibration</string>
<string name="mmoptions_feedback_vibration_summary">Slight vibration when blocks are destroyed</string> <string name="mmoptions_feedback_vibration_summary">Slight vibration when blocks are destroyed</string>
<string name="mmoptions_gfx_fancygraphics_title">Fancy graphics</string> <string name="mmoptions_gfx_fancygraphics_title">Fancy graphics</string>
<string name="mmoptions_gfx_fancygraphics_summary"></string> <string name="mmoptions_gfx_fancygraphics_summary"></string>
<string name="mmoptions_gfx_fancygraphics_summary_powervr"></string> <string name="mmoptions_gfx_fancygraphics_summary_powervr"></string>
<string name="mmoptions_gfx_lowquality_title">Lower graphics quality</string> <string name="mmoptions_gfx_lowquality_title">Lower graphics quality</string>
<string name="mmoptions_gfx_lowquality_summary">Shorter view distance and disables fancy rendering</string> <string name="mmoptions_gfx_lowquality_summary">Shorter view distance and disables fancy rendering</string>
<string name="mmoptions_game_difficultypeaceful_title">Peaceful mode</string> <string name="mmoptions_game_difficultypeaceful_title">Peaceful mode</string>
<string name="mmoptions_game_difficultypeaceful_summary">No hostile mobs, heal automatically</string> <string name="mmoptions_game_difficultypeaceful_summary">No hostile mobs, heal automatically</string>
</resources> </resources>

View File

@@ -1,105 +1,105 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory <PreferenceCategory
android:title="Multiplayer"> android:title="Multiplayer">
<EditTextPreference <EditTextPreference
android:key="mp_username" android:key="mp_username"
android:title="@string/mmoptions_mp_username_title" android:title="@string/mmoptions_mp_username_title"
android:summary="" android:summary=""
android:dialogTitle="@string/mmoptions_mp_username_dialog" android:dialogTitle="@string/mmoptions_mp_username_dialog"
android:defaultValue="Steve" android:defaultValue="Steve"
android:singleLine="true" /> android:singleLine="true" />
<CheckBoxPreference <CheckBoxPreference
android:key="mp_server_visible_default" android:key="mp_server_visible_default"
android:title="@string/mmoptions_mp_server_visible_default_title" android:title="@string/mmoptions_mp_server_visible_default_title"
android:summary="" android:summary=""
android:defaultValue="true" android:defaultValue="true"
/> />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:key="category_graphics" android:key="category_graphics"
android:title="Graphics"> android:title="Graphics">
<CheckBoxPreference <CheckBoxPreference
android:key="gfx_fancygraphics" android:key="gfx_fancygraphics"
android:title="@string/mmoptions_gfx_fancygraphics_title" android:title="@string/mmoptions_gfx_fancygraphics_title"
android:summary="@string/mmoptions_gfx_fancygraphics_summary" android:summary="@string/mmoptions_gfx_fancygraphics_summary"
android:defaultValue="false" android:defaultValue="false"
/> />
<CheckBoxPreference <CheckBoxPreference
android:key="gfx_lowquality" android:key="gfx_lowquality"
android:title="@string/mmoptions_gfx_lowquality_title" android:title="@string/mmoptions_gfx_lowquality_title"
android:summary="@string/mmoptions_gfx_lowquality_summary" android:summary="@string/mmoptions_gfx_lowquality_summary"
android:defaultValue="true" android:defaultValue="true"
/> />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="Controls"> android:title="Controls">
<com.mojang.android.preferences.SliderPreference <com.mojang.android.preferences.SliderPreference
android:key="ctrl_sensitivity" android:key="ctrl_sensitivity"
android:title="@string/mmoptions_ctrl_sensitivity_title" android:title="@string/mmoptions_ctrl_sensitivity_title"
android:max="100" android:max="100"
android:summary="" android:summary=""
android:defaultValue="50" android:defaultValue="50"
android:enabled="true" android:enabled="true"
/> />
<CheckBoxPreference <CheckBoxPreference
android:key="ctrl_invertmouse" android:key="ctrl_invertmouse"
android:title="@string/mmoptions_ctrl_invertmouse_title" android:title="@string/mmoptions_ctrl_invertmouse_title"
android:summary="" android:summary=""
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
/> />
<CheckBoxPreference <CheckBoxPreference
android:key="ctrl_islefthanded" android:key="ctrl_islefthanded"
android:title="@string/mmoptions_ctrl_islefthanded_title" android:title="@string/mmoptions_ctrl_islefthanded_title"
android:summary="" android:summary=""
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
/> />
<CheckBoxPreference <CheckBoxPreference
android:key="ctrl_usetouchscreen" android:key="ctrl_usetouchscreen"
android:title="@string/mmoptions_ctrl_usetouchscreen_title" android:title="@string/mmoptions_ctrl_usetouchscreen_title"
android:summary="" android:summary=""
android:defaultValue="true" android:defaultValue="true"
android:enabled="false" android:enabled="false"
/> />
<CheckBoxPreference <CheckBoxPreference
android:key="ctrl_usetouchjoypad" android:key="ctrl_usetouchjoypad"
android:title="@string/mmoptions_ctrl_usetouchjoypad_title" android:title="@string/mmoptions_ctrl_usetouchjoypad_title"
android:summary="" android:summary=""
android:defaultValue="false" android:defaultValue="false"
android:enabled="true" android:enabled="true"
/> />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="Feedback"> android:title="Feedback">
<CheckBoxPreference <CheckBoxPreference
android:key="feedback_vibration" android:key="feedback_vibration"
android:title="@string/mmoptions_feedback_vibration_title" android:title="@string/mmoptions_feedback_vibration_title"
android:summary="@string/mmoptions_feedback_vibration_summary" android:summary="@string/mmoptions_feedback_vibration_summary"
android:defaultValue="true" android:defaultValue="true"
android:enabled="true" android:enabled="true"
/> />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="Game"> android:title="Game">
<CheckBoxPreference <CheckBoxPreference
android:key="game_difficultypeaceful" android:key="game_difficultypeaceful"
android:title="@string/mmoptions_game_difficultypeaceful_title" android:title="@string/mmoptions_game_difficultypeaceful_title"
android:summary="@string/mmoptions_game_difficultypeaceful_summary" android:summary="@string/mmoptions_game_difficultypeaceful_summary"
android:defaultValue="false" android:defaultValue="false"
/> />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View File

@@ -1,221 +1,221 @@
package com.mojang.minecraftpe.sound; package com.mojang.minecraftpe.sound;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import android.content.Context; import android.content.Context;
import android.media.SoundPool; import android.media.SoundPool;
import com.mojang.minecraftpe.R; import com.mojang.minecraftpe.R;
public class SoundPlayer public class SoundPlayer
{ {
public SoundPlayer(Context c, int streamType) { public SoundPlayer(Context c, int streamType) {
_context = c; _context = c;
_stream = streamType; _stream = streamType;
_random = new Random(); _random = new Random();
_pool = new SoundPool(4, _stream, 0); _pool = new SoundPool(4, _stream, 0);
_init(); _init();
} }
private void _init() { private void _init() {
// Sounds that needs to be preloaded (although asynchronous :p) // Sounds that needs to be preloaded (although asynchronous :p)
SoundId[] preLoaded = { SoundId[] preLoaded = {
new SoundId(R.raw.click, "random.click"), new SoundId(R.raw.click, "random.click"),
new SoundId(R.raw.explode, "random.explode"), new SoundId(R.raw.explode, "random.explode"),
new SoundId(R.raw.splash, "random.splash"), new SoundId(R.raw.splash, "random.splash"),
new SoundId(R.raw.hurt, "random.hurt"), new SoundId(R.raw.hurt, "random.hurt"),
new SoundId(R.raw.pop, "random.pop"), new SoundId(R.raw.pop, "random.pop"),
new SoundId(R.raw.door_open, "random.door_open"), new SoundId(R.raw.door_open, "random.door_open"),
new SoundId(R.raw.door_close, "random.door_close"), new SoundId(R.raw.door_close, "random.door_close"),
new SoundId(R.raw.cloth1, "step.cloth"), new SoundId(R.raw.cloth1, "step.cloth"),
new SoundId(R.raw.cloth2, "step.cloth"), new SoundId(R.raw.cloth2, "step.cloth"),
new SoundId(R.raw.cloth3, "step.cloth"), new SoundId(R.raw.cloth3, "step.cloth"),
new SoundId(R.raw.cloth4, "step.cloth"), new SoundId(R.raw.cloth4, "step.cloth"),
new SoundId(R.raw.glass1, "random.glass"), new SoundId(R.raw.glass1, "random.glass"),
new SoundId(R.raw.glass2, "random.glass"), new SoundId(R.raw.glass2, "random.glass"),
new SoundId(R.raw.glass3, "random.glass"), new SoundId(R.raw.glass3, "random.glass"),
new SoundId(R.raw.grass1, "step.grass"), new SoundId(R.raw.grass1, "step.grass"),
new SoundId(R.raw.grass2, "step.grass"), new SoundId(R.raw.grass2, "step.grass"),
new SoundId(R.raw.grass3, "step.grass"), new SoundId(R.raw.grass3, "step.grass"),
new SoundId(R.raw.grass4, "step.grass"), new SoundId(R.raw.grass4, "step.grass"),
//new SoundId(R.raw.gravel1, "step.gravel"), //new SoundId(R.raw.gravel1, "step.gravel"),
new SoundId(R.raw.gravel2, "step.gravel"), new SoundId(R.raw.gravel2, "step.gravel"),
new SoundId(R.raw.gravel3, "step.gravel"), new SoundId(R.raw.gravel3, "step.gravel"),
new SoundId(R.raw.gravel4, "step.gravel"), new SoundId(R.raw.gravel4, "step.gravel"),
new SoundId(R.raw.sand1, "step.sand"), new SoundId(R.raw.sand1, "step.sand"),
new SoundId(R.raw.sand2, "step.sand"), new SoundId(R.raw.sand2, "step.sand"),
new SoundId(R.raw.sand3, "step.sand"), new SoundId(R.raw.sand3, "step.sand"),
new SoundId(R.raw.sand4, "step.sand"), new SoundId(R.raw.sand4, "step.sand"),
new SoundId(R.raw.stone1, "step.stone"), new SoundId(R.raw.stone1, "step.stone"),
new SoundId(R.raw.stone2, "step.stone"), new SoundId(R.raw.stone2, "step.stone"),
new SoundId(R.raw.stone3, "step.stone"), new SoundId(R.raw.stone3, "step.stone"),
new SoundId(R.raw.stone4, "step.stone"), new SoundId(R.raw.stone4, "step.stone"),
new SoundId(R.raw.wood1, "step.wood"), new SoundId(R.raw.wood1, "step.wood"),
new SoundId(R.raw.wood2, "step.wood"), new SoundId(R.raw.wood2, "step.wood"),
new SoundId(R.raw.wood3, "step.wood"), new SoundId(R.raw.wood3, "step.wood"),
new SoundId(R.raw.wood4, "step.wood"), new SoundId(R.raw.wood4, "step.wood"),
new SoundId(R.raw.sheep1, "mob.sheep"), new SoundId(R.raw.sheep1, "mob.sheep"),
new SoundId(R.raw.sheep2, "mob.sheep"), new SoundId(R.raw.sheep2, "mob.sheep"),
new SoundId(R.raw.sheep3, "mob.sheep"), new SoundId(R.raw.sheep3, "mob.sheep"),
new SoundId(R.raw.chicken2, "mob.chicken"), new SoundId(R.raw.chicken2, "mob.chicken"),
new SoundId(R.raw.chicken3, "mob.chicken"), new SoundId(R.raw.chicken3, "mob.chicken"),
new SoundId(R.raw.chickenhurt1, "mob.chickenhurt"), new SoundId(R.raw.chickenhurt1, "mob.chickenhurt"),
new SoundId(R.raw.chickenhurt2, "mob.chickenhurt"), new SoundId(R.raw.chickenhurt2, "mob.chickenhurt"),
new SoundId(R.raw.cow1, "mob.cow"), new SoundId(R.raw.cow1, "mob.cow"),
new SoundId(R.raw.cow2, "mob.cow"), new SoundId(R.raw.cow2, "mob.cow"),
new SoundId(R.raw.cow3, "mob.cow"), new SoundId(R.raw.cow3, "mob.cow"),
new SoundId(R.raw.cow4, "mob.cow"), new SoundId(R.raw.cow4, "mob.cow"),
new SoundId(R.raw.cowhurt1, "mob.cowhurt"), new SoundId(R.raw.cowhurt1, "mob.cowhurt"),
new SoundId(R.raw.cowhurt2, "mob.cowhurt"), new SoundId(R.raw.cowhurt2, "mob.cowhurt"),
new SoundId(R.raw.pig1, "mob.pig"), new SoundId(R.raw.pig1, "mob.pig"),
new SoundId(R.raw.pig2, "mob.pig"), new SoundId(R.raw.pig2, "mob.pig"),
new SoundId(R.raw.pig3, "mob.pig"), new SoundId(R.raw.pig3, "mob.pig"),
new SoundId(R.raw.pigdeath, "mob.pigdeath"), new SoundId(R.raw.pigdeath, "mob.pigdeath"),
new SoundId(R.raw.zombie1, "mob.zombie"), new SoundId(R.raw.zombie1, "mob.zombie"),
new SoundId(R.raw.zombie2, "mob.zombie"), new SoundId(R.raw.zombie2, "mob.zombie"),
new SoundId(R.raw.zombie3, "mob.zombie"), new SoundId(R.raw.zombie3, "mob.zombie"),
new SoundId(R.raw.zombiedeath, "mob.zombiedeath"), new SoundId(R.raw.zombiedeath, "mob.zombiedeath"),
new SoundId(R.raw.zombiehurt1, "mob.zombiehurt"), new SoundId(R.raw.zombiehurt1, "mob.zombiehurt"),
new SoundId(R.raw.zombiehurt2, "mob.zombiehurt"), new SoundId(R.raw.zombiehurt2, "mob.zombiehurt"),
new SoundId(R.raw.skeleton1, "mob.skeleton"), new SoundId(R.raw.skeleton1, "mob.skeleton"),
new SoundId(R.raw.skeleton2, "mob.skeleton"), new SoundId(R.raw.skeleton2, "mob.skeleton"),
new SoundId(R.raw.skeleton3, "mob.skeleton"), new SoundId(R.raw.skeleton3, "mob.skeleton"),
new SoundId(R.raw.skeletonhurt1, "mob.skeletonhurt"), new SoundId(R.raw.skeletonhurt1, "mob.skeletonhurt"),
new SoundId(R.raw.skeletonhurt2, "mob.skeletonhurt"), new SoundId(R.raw.skeletonhurt2, "mob.skeletonhurt"),
new SoundId(R.raw.skeletonhurt3, "mob.skeletonhurt"), new SoundId(R.raw.skeletonhurt3, "mob.skeletonhurt"),
new SoundId(R.raw.skeletonhurt4, "mob.skeletonhurt"), new SoundId(R.raw.skeletonhurt4, "mob.skeletonhurt"),
new SoundId(R.raw.spider1, "mob.spider"), new SoundId(R.raw.spider1, "mob.spider"),
new SoundId(R.raw.spider2, "mob.spider"), new SoundId(R.raw.spider2, "mob.spider"),
new SoundId(R.raw.spider3, "mob.spider"), new SoundId(R.raw.spider3, "mob.spider"),
new SoundId(R.raw.spider4, "mob.spider"), new SoundId(R.raw.spider4, "mob.spider"),
new SoundId(R.raw.spiderdeath, "mob.spiderdeath"), new SoundId(R.raw.spiderdeath, "mob.spiderdeath"),
new SoundId(R.raw.fallbig1, "damage.fallbig"), new SoundId(R.raw.fallbig1, "damage.fallbig"),
new SoundId(R.raw.fallbig2, "damage.fallbig"), new SoundId(R.raw.fallbig2, "damage.fallbig"),
new SoundId(R.raw.fallsmall, "damage.fallsmall"), new SoundId(R.raw.fallsmall, "damage.fallsmall"),
new SoundId(R.raw.bow, "random.bow"), new SoundId(R.raw.bow, "random.bow"),
new SoundId(R.raw.bowhit1, "random.bowhit"), new SoundId(R.raw.bowhit1, "random.bowhit"),
new SoundId(R.raw.bowhit2, "random.bowhit"), new SoundId(R.raw.bowhit2, "random.bowhit"),
new SoundId(R.raw.bowhit3, "random.bowhit"), new SoundId(R.raw.bowhit3, "random.bowhit"),
new SoundId(R.raw.bowhit4, "random.bowhit"), new SoundId(R.raw.bowhit4, "random.bowhit"),
new SoundId(R.raw.creeper1, "mob.creeper"), new SoundId(R.raw.creeper1, "mob.creeper"),
new SoundId(R.raw.creeper2, "mob.creeper"), new SoundId(R.raw.creeper2, "mob.creeper"),
new SoundId(R.raw.creeper3, "mob.creeper"), new SoundId(R.raw.creeper3, "mob.creeper"),
new SoundId(R.raw.creeper4, "mob.creeper"), new SoundId(R.raw.creeper4, "mob.creeper"),
new SoundId(R.raw.creeperdeath, "mob.creeperdeath"), new SoundId(R.raw.creeperdeath, "mob.creeperdeath"),
new SoundId(R.raw.eat1, "random.eat"), new SoundId(R.raw.eat1, "random.eat"),
new SoundId(R.raw.eat2, "random.eat"), new SoundId(R.raw.eat2, "random.eat"),
new SoundId(R.raw.eat3, "random.eat"), new SoundId(R.raw.eat3, "random.eat"),
new SoundId(R.raw.fuse, "random.fuse"), new SoundId(R.raw.fuse, "random.fuse"),
new SoundId(R.raw.zpig1, "mob.zombiepig.zpig"), new SoundId(R.raw.zpig1, "mob.zombiepig.zpig"),
new SoundId(R.raw.zpig2, "mob.zombiepig.zpig"), new SoundId(R.raw.zpig2, "mob.zombiepig.zpig"),
new SoundId(R.raw.zpig3, "mob.zombiepig.zpig"), new SoundId(R.raw.zpig3, "mob.zombiepig.zpig"),
new SoundId(R.raw.zpig4, "mob.zombiepig.zpig"), new SoundId(R.raw.zpig4, "mob.zombiepig.zpig"),
new SoundId(R.raw.zpigangry1, "mob.zombiepig.zpigangry"), new SoundId(R.raw.zpigangry1, "mob.zombiepig.zpigangry"),
new SoundId(R.raw.zpigangry2, "mob.zombiepig.zpigangry"), new SoundId(R.raw.zpigangry2, "mob.zombiepig.zpigangry"),
new SoundId(R.raw.zpigangry3, "mob.zombiepig.zpigangry"), new SoundId(R.raw.zpigangry3, "mob.zombiepig.zpigangry"),
new SoundId(R.raw.zpigangry4, "mob.zombiepig.zpigangry"), new SoundId(R.raw.zpigangry4, "mob.zombiepig.zpigangry"),
new SoundId(R.raw.zpigdeath, "mob.zombiepig.zpigdeath"), new SoundId(R.raw.zpigdeath, "mob.zombiepig.zpigdeath"),
new SoundId(R.raw.zpighurt1, "mob.zombiepig.zpighurt"), new SoundId(R.raw.zpighurt1, "mob.zombiepig.zpighurt"),
new SoundId(R.raw.zpighurt2, "mob.zombiepig.zpighurt"), new SoundId(R.raw.zpighurt2, "mob.zombiepig.zpighurt"),
}; };
for (SoundId s: preLoaded) { for (SoundId s: preLoaded) {
load(s.name, s.soundId); load(s.name, s.soundId);
} }
// Sounds that are loaded in a separate thread // Sounds that are loaded in a separate thread
} }
// public void loadWithAlias(String filename, String alias) { // public void loadWithAlias(String filename, String alias) {
// int id = loadRaw(filename); // int id = loadRaw(filename);
// addRaw(new SoundId(id, alias)); // addRaw(new SoundId(id, alias));
// } // }
public void play(String s, float volume, float pitch) { public void play(String s, float volume, float pitch) {
SoundId sound = get(s);//load(s); SoundId sound = get(s);//load(s);
if (sound != null) { if (sound != null) {
volume *= getCurrentStreamVolume(); volume *= getCurrentStreamVolume();
//System.out.println("playing sound id: " + sound.soundId); //System.out.println("playing sound id: " + sound.soundId);
if (s.equals("step.sand") || s.equals("step.gravel")) volume *= 0.5f; if (s.equals("step.sand") || s.equals("step.gravel")) volume *= 0.5f;
_pool.play(sound.soundId, volume, volume, 0, 0, pitch); _pool.play(sound.soundId, volume, volume, 0, 0, pitch);
} }
} }
private SoundId get(String s) { private SoundId get(String s) {
List<SoundId> sounds = _sounds.get( s ); List<SoundId> sounds = _sounds.get( s );
if (sounds == null) return null; if (sounds == null) return null;
return sounds.get(_random.nextInt(sounds.size())); return sounds.get(_random.nextInt(sounds.size()));
} }
public float getCurrentStreamVolume() { public float getCurrentStreamVolume() {
return 2.5f; return 2.5f;
//AudioManager mgr = (AudioManager)_context.getSystemService(Context.AUDIO_SERVICE); //AudioManager mgr = (AudioManager)_context.getSystemService(Context.AUDIO_SERVICE);
//return ((float)mgr.getStreamVolume(_stream)) / mgr.getStreamMaxVolume(_stream); //return ((float)mgr.getStreamVolume(_stream)) / mgr.getStreamMaxVolume(_stream);
} }
synchronized public SoundId load(String id, int resId) { synchronized public SoundId load(String id, int resId) {
if (id == null) if (id == null)
return null; return null;
List<SoundId> sounds = _sounds.get(id); List<SoundId> sounds = _sounds.get(id);
SoundId soundId = null; SoundId soundId = null;
if (sounds == null) { if (sounds == null) {
sounds = new ArrayList<SoundId>(); sounds = new ArrayList<SoundId>();
_sounds.put(id, sounds); _sounds.put(id, sounds);
} }
for (SoundId sid : sounds) for (SoundId sid : sounds)
if (sid.soundId == resId) if (sid.soundId == resId)
return sid; return sid;
int snd = _pool.load(_context, resId, DefaultPriority); int snd = _pool.load(_context, resId, DefaultPriority);
soundId = new SoundId(snd, id); soundId = new SoundId(snd, id);
sounds.add(soundId); sounds.add(soundId);
return soundId; return soundId;
} }
private Context _context; private Context _context;
private Random _random; private Random _random;
private int _stream; private int _stream;
private SoundPool _pool; private SoundPool _pool;
private Map<String, List<SoundId>> _sounds = new HashMap<String, List<SoundId>>(); private Map<String, List<SoundId>> _sounds = new HashMap<String, List<SoundId>>();
static private final int DefaultPriority = 1; static private final int DefaultPriority = 1;
public class SoundId { public class SoundId {
SoundId(int soundId, String name) { SoundId(int soundId, String name) {
this.soundId = soundId; this.soundId = soundId;
this.name = name; this.name = name;
} }
int soundId; int soundId;
String name; String name;
} }
} }

View File

@@ -1,14 +1,14 @@
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := RakNet LOCAL_MODULE := RakNet
MY_PREFIX := $(LOCAL_PATH)/RaknetSources/ MY_PREFIX := $(LOCAL_PATH)/RaknetSources/
MY_SOURCES := $(wildcard $(MY_PREFIX)*.cpp) MY_SOURCES := $(wildcard $(MY_PREFIX)*.cpp)
LOCAL_SRC_FILES += $(MY_SOURCES:$(MY_PREFIX)%=RaknetSources/%) LOCAL_SRC_FILES += $(MY_SOURCES:$(MY_PREFIX)%=RaknetSources/%)
LOCAL_CFLAGS := -Wno-psabi $(LOCAL_CFLAGS) LOCAL_CFLAGS := -Wno-psabi $(LOCAL_CFLAGS)
LOCAL_CPPFLAGS += -frtti LOCAL_CPPFLAGS += -frtti
include $(BUILD_STATIC_LIBRARY) include $(BUILD_STATIC_LIBRARY)

View File

@@ -1,4 +1,4 @@
APP_PLATFORM := android-8 APP_PLATFORM := android-8
APP_STL := stlport_static APP_STL := stlport_static
APP_OPTIM := release APP_OPTIM := release
APP_ABI := armeabi-v7a APP_ABI := armeabi-v7a

View File

@@ -1,23 +1,23 @@
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
/// ///
#ifndef __AUTOPATCHER_PATCH_CONTEXT_H #ifndef __AUTOPATCHER_PATCH_CONTEXT_H
#define __AUTOPATCHER_PATCH_CONTEXT_H #define __AUTOPATCHER_PATCH_CONTEXT_H
enum PatchContext enum PatchContext
{ {
PC_HASH_1_WITH_PATCH, PC_HASH_1_WITH_PATCH,
PC_HASH_2_WITH_PATCH, PC_HASH_2_WITH_PATCH,
PC_WRITE_FILE, PC_WRITE_FILE,
PC_ERROR_FILE_WRITE_FAILURE, PC_ERROR_FILE_WRITE_FAILURE,
PC_ERROR_PATCH_TARGET_MISSING, PC_ERROR_PATCH_TARGET_MISSING,
PC_ERROR_PATCH_APPLICATION_FAILURE, PC_ERROR_PATCH_APPLICATION_FAILURE,
PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE, PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE,
PC_NOTICE_WILL_COPY_ON_RESTART, PC_NOTICE_WILL_COPY_ON_RESTART,
PC_NOTICE_FILE_DOWNLOADED, PC_NOTICE_FILE_DOWNLOADED,
PC_NOTICE_FILE_DOWNLOADED_PATCH, PC_NOTICE_FILE_DOWNLOADED_PATCH,
}; };
#endif #endif

View File

@@ -1,72 +1,72 @@
/// ///
/// \file AutopatcherRepositoryInterface.h /// \file AutopatcherRepositoryInterface.h
/// \brief An interface used by AutopatcherServer to get the data necessary to run an autopatcher. /// \brief An interface used by AutopatcherServer to get the data necessary to run an autopatcher.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
/// ///
#ifndef __AUTOPATCHER_REPOSITORY_INTERFACE_H #ifndef __AUTOPATCHER_REPOSITORY_INTERFACE_H
#define __AUTOPATCHER_REPOSITORY_INTERFACE_H #define __AUTOPATCHER_REPOSITORY_INTERFACE_H
#include "IncrementalReadInterface.h" #include "IncrementalReadInterface.h"
#include "SimpleMutex.h" #include "SimpleMutex.h"
namespace RakNet namespace RakNet
{ {
/// Forward declarations /// Forward declarations
class FileList; class FileList;
class BitStream; class BitStream;
/// An interface used by AutopatcherServer to get the data necessary to run an autopatcher. This is up to you to implement for custom repository solutions. /// An interface used by AutopatcherServer to get the data necessary to run an autopatcher. This is up to you to implement for custom repository solutions.
class AutopatcherRepositoryInterface : public IncrementalReadInterface class AutopatcherRepositoryInterface : public IncrementalReadInterface
{ {
public: public:
/// Get list of files added and deleted since a certain date. This is used by AutopatcherServer and not usually explicitly called. /// Get list of files added and deleted since a certain date. This is used by AutopatcherServer and not usually explicitly called.
/// \param[in] applicationName A null terminated string identifying the application /// \param[in] applicationName A null terminated string identifying the application
/// \param[out] addedFiles A list of the current versions of filenames with hashes as their data that were created after \a sinceData /// \param[out] addedFiles A list of the current versions of filenames with hashes as their data that were created after \a sinceData
/// \param[out] deletedFiles A list of the current versions of filenames that were deleted after \a sinceData /// \param[out] deletedFiles A list of the current versions of filenames that were deleted after \a sinceData
/// \param[in] An input date, in whatever format your repository uses /// \param[in] An input date, in whatever format your repository uses
/// \param[out] currentDate The current server date, in whatever format your repository uses /// \param[out] currentDate The current server date, in whatever format your repository uses
/// \return True on success, false on failure. /// \return True on success, false on failure.
virtual bool GetChangelistSinceDate(const char *applicationName, FileList *addedFiles, FileList *deletedFiles, double sinceDate)=0; virtual bool GetChangelistSinceDate(const char *applicationName, FileList *addedFiles, FileList *deletedFiles, double sinceDate)=0;
/// Get patches (or files) for every file in input, assuming that input has a hash for each of those files. /// Get patches (or files) for every file in input, assuming that input has a hash for each of those files.
/// \param[in] applicationName A null terminated string identifying the application /// \param[in] applicationName A null terminated string identifying the application
/// \param[in] input A list of files with SHA1_LENGTH byte hashes to get from the database. /// \param[in] input A list of files with SHA1_LENGTH byte hashes to get from the database.
/// \param[out] patchList You should return list of files with either the filedata or the patch. This is a subset of \a input. The context data for each file will be either PC_WRITE_FILE (to just write the file) or PC_HASH_WITH_PATCH (to patch). If PC_HASH_WITH_PATCH, then the file contains a SHA1_LENGTH byte patch followed by the hash. The datalength is patchlength + SHA1_LENGTH /// \param[out] patchList You should return list of files with either the filedata or the patch. This is a subset of \a input. The context data for each file will be either PC_WRITE_FILE (to just write the file) or PC_HASH_WITH_PATCH (to patch). If PC_HASH_WITH_PATCH, then the file contains a SHA1_LENGTH byte patch followed by the hash. The datalength is patchlength + SHA1_LENGTH
/// \param[out] currentDate The current server date, in whatever format your repository uses /// \param[out] currentDate The current server date, in whatever format your repository uses
/// \return True on success, false on failure. /// \return True on success, false on failure.
virtual bool GetPatches(const char *applicationName, FileList *input, FileList *patchList)=0; virtual bool GetPatches(const char *applicationName, FileList *input, FileList *patchList)=0;
/// For the most recent update, return files that were patched, added, or deleted. For files that were patched, return both the patch in \a patchedFiles and the current version in \a updatedFiles /// For the most recent update, return files that were patched, added, or deleted. For files that were patched, return both the patch in \a patchedFiles and the current version in \a updatedFiles
/// The cache will be used if the client last patched between \a priorRowPatchTime and \a mostRecentRowPatchTime /// The cache will be used if the client last patched between \a priorRowPatchTime and \a mostRecentRowPatchTime
/// No files changed will be returned to the client if the client last patched after mostRecentRowPatchTime /// No files changed will be returned to the client if the client last patched after mostRecentRowPatchTime
/// \param[in,out] applicationName Name of the application to get patches for. If empty, uses the most recently updated application, and the string will be updated to reflect this name. /// \param[in,out] applicationName Name of the application to get patches for. If empty, uses the most recently updated application, and the string will be updated to reflect this name.
/// \param[out] patchedFiles Given the most recent update, if a file was patched, add it to this list. The context data for each file will be PC_HASH_WITH_PATCH. The first 4 bytes of data should be a hash of the file being patched. The second 4 bytes should be the hash of the file after the patch. The remaining bytes should be the patch itself. /// \param[out] patchedFiles Given the most recent update, if a file was patched, add it to this list. The context data for each file will be PC_HASH_WITH_PATCH. The first 4 bytes of data should be a hash of the file being patched. The second 4 bytes should be the hash of the file after the patch. The remaining bytes should be the patch itself.
/// \param[out] updatedFiles The current value of the file. List should have the same length and order as \a patchedFiles /// \param[out] updatedFiles The current value of the file. List should have the same length and order as \a patchedFiles
/// \param[out] updatedFileHashes The hash of the current value of the file. List should have the same length and order as \a patchedFiles /// \param[out] updatedFileHashes The hash of the current value of the file. List should have the same length and order as \a patchedFiles
/// \param[out] deletedFiles Files that were deleted in the last patch. /// \param[out] deletedFiles Files that were deleted in the last patch.
/// \param[out] priorRowPatchTime When the patch before the most recent patch took place. 0 means never. /// \param[out] priorRowPatchTime When the patch before the most recent patch took place. 0 means never.
/// \param[out] mostRecentRowPatchTime When the most recent patch took place. 0 means never. /// \param[out] mostRecentRowPatchTime When the most recent patch took place. 0 means never.
/// \return true on success, false on failure /// \return true on success, false on failure
virtual bool GetMostRecentChangelistWithPatches( virtual bool GetMostRecentChangelistWithPatches(
RakNet::RakString &applicationName, RakNet::RakString &applicationName,
FileList *patchedFiles, FileList *patchedFiles,
FileList *updatedFiles, FileList *updatedFiles,
FileList *updatedFileHashes, FileList *updatedFileHashes,
FileList *deletedFiles, FileList *deletedFiles,
double *priorRowPatchTime, double *priorRowPatchTime,
double *mostRecentRowPatchTime)=0; double *mostRecentRowPatchTime)=0;
/// \return Whatever this function returns is sent from the AutopatcherServer to the AutopatcherClient when one of the above functions returns false. /// \return Whatever this function returns is sent from the AutopatcherServer to the AutopatcherClient when one of the above functions returns false.
virtual const char *GetLastError(void) const=0; virtual const char *GetLastError(void) const=0;
/// \return Passed to FileListTransfer::Send() as the _chunkSize parameter. /// \return Passed to FileListTransfer::Send() as the _chunkSize parameter.
virtual const int GetIncrementalReadChunkSize(void) const=0; virtual const int GetIncrementalReadChunkSize(void) const=0;
}; };
} // namespace RakNet } // namespace RakNet
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,332 +1,332 @@
#include "CCRakNetSlidingWindow.h" #include "CCRakNetSlidingWindow.h"
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL==1 #if USE_SLIDING_WINDOW_CONGESTION_CONTROL==1
static const double UNSET_TIME_US=-1; static const double UNSET_TIME_US=-1;
#if CC_TIME_TYPE_BYTES==4 #if CC_TIME_TYPE_BYTES==4
static const CCTimeType SYN=10; static const CCTimeType SYN=10;
#else #else
static const CCTimeType SYN=10000; static const CCTimeType SYN=10000;
#endif #endif
#include "MTUSize.h" #include "MTUSize.h"
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include "RakAssert.h" #include "RakAssert.h"
#include "RakAlloca.h" #include "RakAlloca.h"
using namespace RakNet; using namespace RakNet;
// ****************************************************** PUBLIC METHODS ****************************************************** // ****************************************************** PUBLIC METHODS ******************************************************
CCRakNetSlidingWindow::CCRakNetSlidingWindow() CCRakNetSlidingWindow::CCRakNetSlidingWindow()
{ {
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
CCRakNetSlidingWindow::~CCRakNetSlidingWindow() CCRakNetSlidingWindow::~CCRakNetSlidingWindow()
{ {
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::Init(CCTimeType curTime, uint32_t maxDatagramPayload) void CCRakNetSlidingWindow::Init(CCTimeType curTime, uint32_t maxDatagramPayload)
{ {
(void) curTime; (void) curTime;
RTT=UNSET_TIME_US; RTT=UNSET_TIME_US;
MAXIMUM_MTU_INCLUDING_UDP_HEADER=maxDatagramPayload; MAXIMUM_MTU_INCLUDING_UDP_HEADER=maxDatagramPayload;
cwnd=maxDatagramPayload; cwnd=maxDatagramPayload;
ssThresh=0.0; ssThresh=0.0;
oldestUnsentAck=0; oldestUnsentAck=0;
nextDatagramSequenceNumber=0; nextDatagramSequenceNumber=0;
nextCongestionControlBlock=0; nextCongestionControlBlock=0;
backoffThisBlock=speedUpThisBlock=false; backoffThisBlock=speedUpThisBlock=false;
expectedNextSequenceNumber=0; expectedNextSequenceNumber=0;
_isContinuousSend=false; _isContinuousSend=false;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::Update(CCTimeType curTime, bool hasDataToSendOrResend) void CCRakNetSlidingWindow::Update(CCTimeType curTime, bool hasDataToSendOrResend)
{ {
(void) curTime; (void) curTime;
(void) hasDataToSendOrResend; (void) hasDataToSendOrResend;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
int CCRakNetSlidingWindow::GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend) int CCRakNetSlidingWindow::GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend)
{ {
(void) curTime; (void) curTime;
(void) isContinuousSend; (void) isContinuousSend;
(void) timeSinceLastTick; (void) timeSinceLastTick;
return unacknowledgedBytes; return unacknowledgedBytes;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
int CCRakNetSlidingWindow::GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend) int CCRakNetSlidingWindow::GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend)
{ {
(void) curTime; (void) curTime;
(void) timeSinceLastTick; (void) timeSinceLastTick;
_isContinuousSend=isContinuousSend; _isContinuousSend=isContinuousSend;
if (unacknowledgedBytes<=cwnd) if (unacknowledgedBytes<=cwnd)
return (int) (cwnd-unacknowledgedBytes); return (int) (cwnd-unacknowledgedBytes);
else else
return 0; return 0;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
bool CCRakNetSlidingWindow::ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick) bool CCRakNetSlidingWindow::ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick)
{ {
CCTimeType rto = GetSenderRTOForACK(); CCTimeType rto = GetSenderRTOForACK();
(void) estimatedTimeToNextTick; (void) estimatedTimeToNextTick;
// iphone crashes on comparison between double and int64 http://www.jenkinssoftware.com/forum/index.php?topic=2717.0 // iphone crashes on comparison between double and int64 http://www.jenkinssoftware.com/forum/index.php?topic=2717.0
if (rto==(CCTimeType) UNSET_TIME_US) if (rto==(CCTimeType) UNSET_TIME_US)
{ {
// Unknown how long until the remote system will retransmit, so better send right away // Unknown how long until the remote system will retransmit, so better send right away
return true; return true;
} }
return curTime >= oldestUnsentAck + SYN; return curTime >= oldestUnsentAck + SYN;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
DatagramSequenceNumberType CCRakNetSlidingWindow::GetNextDatagramSequenceNumber(void) DatagramSequenceNumberType CCRakNetSlidingWindow::GetNextDatagramSequenceNumber(void)
{ {
return nextDatagramSequenceNumber; return nextDatagramSequenceNumber;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
DatagramSequenceNumberType CCRakNetSlidingWindow::GetAndIncrementNextDatagramSequenceNumber(void) DatagramSequenceNumberType CCRakNetSlidingWindow::GetAndIncrementNextDatagramSequenceNumber(void)
{ {
DatagramSequenceNumberType dsnt=nextDatagramSequenceNumber; DatagramSequenceNumberType dsnt=nextDatagramSequenceNumber;
nextDatagramSequenceNumber++; nextDatagramSequenceNumber++;
return dsnt; return dsnt;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::OnSendBytes(CCTimeType curTime, uint32_t numBytes) void CCRakNetSlidingWindow::OnSendBytes(CCTimeType curTime, uint32_t numBytes)
{ {
(void) curTime; (void) curTime;
(void) numBytes; (void) numBytes;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime) void CCRakNetSlidingWindow::OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime)
{ {
(void) curTime; (void) curTime;
(void) sizeInBytes; (void) sizeInBytes;
(void) datagramSequenceNumber; (void) datagramSequenceNumber;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
bool CCRakNetSlidingWindow::OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount) bool CCRakNetSlidingWindow::OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount)
{ {
(void) curTime; (void) curTime;
(void) sizeInBytes; (void) sizeInBytes;
(void) isContinuousSend; (void) isContinuousSend;
if (oldestUnsentAck==0) if (oldestUnsentAck==0)
oldestUnsentAck=curTime; oldestUnsentAck=curTime;
if (datagramSequenceNumber==expectedNextSequenceNumber) if (datagramSequenceNumber==expectedNextSequenceNumber)
{ {
*skippedMessageCount=0; *skippedMessageCount=0;
expectedNextSequenceNumber=datagramSequenceNumber+(DatagramSequenceNumberType)1; expectedNextSequenceNumber=datagramSequenceNumber+(DatagramSequenceNumberType)1;
} }
else if (GreaterThan(datagramSequenceNumber, expectedNextSequenceNumber)) else if (GreaterThan(datagramSequenceNumber, expectedNextSequenceNumber))
{ {
*skippedMessageCount=datagramSequenceNumber-expectedNextSequenceNumber; *skippedMessageCount=datagramSequenceNumber-expectedNextSequenceNumber;
// Sanity check, just use timeout resend if this was really valid // Sanity check, just use timeout resend if this was really valid
if (*skippedMessageCount>1000) if (*skippedMessageCount>1000)
{ {
// During testing, the nat punchthrough server got 51200 on the first packet. I have no idea where this comes from, but has happened twice // During testing, the nat punchthrough server got 51200 on the first packet. I have no idea where this comes from, but has happened twice
if (*skippedMessageCount>(uint32_t)50000) if (*skippedMessageCount>(uint32_t)50000)
return false; return false;
*skippedMessageCount=1000; *skippedMessageCount=1000;
} }
expectedNextSequenceNumber=datagramSequenceNumber+(DatagramSequenceNumberType)1; expectedNextSequenceNumber=datagramSequenceNumber+(DatagramSequenceNumberType)1;
} }
else else
{ {
*skippedMessageCount=0; *skippedMessageCount=0;
} }
return true; return true;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::OnResend(CCTimeType curTime) void CCRakNetSlidingWindow::OnResend(CCTimeType curTime)
{ {
(void) curTime; (void) curTime;
if (_isContinuousSend && backoffThisBlock==false && cwnd>MAXIMUM_MTU_INCLUDING_UDP_HEADER*2) if (_isContinuousSend && backoffThisBlock==false && cwnd>MAXIMUM_MTU_INCLUDING_UDP_HEADER*2)
{ {
ssThresh=cwnd/2; ssThresh=cwnd/2;
if (ssThresh<MAXIMUM_MTU_INCLUDING_UDP_HEADER) if (ssThresh<MAXIMUM_MTU_INCLUDING_UDP_HEADER)
ssThresh=MAXIMUM_MTU_INCLUDING_UDP_HEADER; ssThresh=MAXIMUM_MTU_INCLUDING_UDP_HEADER;
cwnd=MAXIMUM_MTU_INCLUDING_UDP_HEADER; cwnd=MAXIMUM_MTU_INCLUDING_UDP_HEADER;
// Only backoff once per period // Only backoff once per period
backoffThisBlock=true; backoffThisBlock=true;
} }
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber) void CCRakNetSlidingWindow::OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber)
{ {
(void) nakSequenceNumber; (void) nakSequenceNumber;
OnResend(curTime); OnResend(curTime);
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber ) void CCRakNetSlidingWindow::OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber )
{ {
(void) _B; (void) _B;
(void) totalUserDataBytesAcked; (void) totalUserDataBytesAcked;
(void) _AS; (void) _AS;
(void) hasBAndAS; (void) hasBAndAS;
(void) curTime; (void) curTime;
(void) rtt; (void) rtt;
RTT=(double) rtt; RTT=(double) rtt;
_isContinuousSend=isContinuousSend; _isContinuousSend=isContinuousSend;
if (isContinuousSend==false) if (isContinuousSend==false)
return; return;
bool isNewCongestionControlPeriod; bool isNewCongestionControlPeriod;
isNewCongestionControlPeriod = GreaterThan(sequenceNumber, nextCongestionControlBlock); isNewCongestionControlPeriod = GreaterThan(sequenceNumber, nextCongestionControlBlock);
if (isNewCongestionControlPeriod) if (isNewCongestionControlPeriod)
{ {
nextCongestionControlBlock=nextDatagramSequenceNumber; nextCongestionControlBlock=nextDatagramSequenceNumber;
backoffThisBlock=false; backoffThisBlock=false;
speedUpThisBlock=false; speedUpThisBlock=false;
} }
if (IsInSlowStart()) if (IsInSlowStart())
{ {
// if (isNewCongestionControlPeriod) // if (isNewCongestionControlPeriod)
{ {
// Keep the number in range to avoid overflow // Keep the number in range to avoid overflow
if (cwnd<10000000) if (cwnd<10000000)
{ {
cwnd*=2; cwnd*=2;
if (cwnd>ssThresh && ssThresh!=0) if (cwnd>ssThresh && ssThresh!=0)
{ {
cwnd=ssThresh; cwnd=ssThresh;
cwnd+=MAXIMUM_MTU_INCLUDING_UDP_HEADER*MAXIMUM_MTU_INCLUDING_UDP_HEADER/cwnd; cwnd+=MAXIMUM_MTU_INCLUDING_UDP_HEADER*MAXIMUM_MTU_INCLUDING_UDP_HEADER/cwnd;
} }
} }
} }
} }
else else
{ {
if (isNewCongestionControlPeriod) if (isNewCongestionControlPeriod)
cwnd+=MAXIMUM_MTU_INCLUDING_UDP_HEADER*MAXIMUM_MTU_INCLUDING_UDP_HEADER/cwnd; cwnd+=MAXIMUM_MTU_INCLUDING_UDP_HEADER*MAXIMUM_MTU_INCLUDING_UDP_HEADER/cwnd;
} }
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::OnDuplicateAck( CCTimeType curTime, DatagramSequenceNumberType sequenceNumber ) void CCRakNetSlidingWindow::OnDuplicateAck( CCTimeType curTime, DatagramSequenceNumberType sequenceNumber )
{ {
(void) sequenceNumber; (void) sequenceNumber;
OnResend(curTime); OnResend(curTime);
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS) void CCRakNetSlidingWindow::OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS)
{ {
(void) curTime; (void) curTime;
(void) _B; (void) _B;
(void) _AS; (void) _AS;
*hasBAndAS=false; *hasBAndAS=false;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::OnSendAck(CCTimeType curTime, uint32_t numBytes) void CCRakNetSlidingWindow::OnSendAck(CCTimeType curTime, uint32_t numBytes)
{ {
(void) curTime; (void) curTime;
(void) numBytes; (void) numBytes;
oldestUnsentAck=0; oldestUnsentAck=0;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::OnSendNACK(CCTimeType curTime, uint32_t numBytes) void CCRakNetSlidingWindow::OnSendNACK(CCTimeType curTime, uint32_t numBytes)
{ {
(void) curTime; (void) curTime;
(void) numBytes; (void) numBytes;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
CCTimeType CCRakNetSlidingWindow::GetRTOForRetransmission(void) const CCTimeType CCRakNetSlidingWindow::GetRTOForRetransmission(void) const
{ {
#if CC_TIME_TYPE_BYTES==4 #if CC_TIME_TYPE_BYTES==4
const CCTimeType maxThreshold=2000; const CCTimeType maxThreshold=2000;
const CCTimeType minThreshold=100; const CCTimeType minThreshold=100;
#else #else
const CCTimeType maxThreshold=2000000; const CCTimeType maxThreshold=2000000;
const CCTimeType minThreshold=100000; const CCTimeType minThreshold=100000;
#endif #endif
if (RTT==UNSET_TIME_US) if (RTT==UNSET_TIME_US)
{ {
return maxThreshold; return maxThreshold;
} }
if (RTT * 3 > maxThreshold) if (RTT * 3 > maxThreshold)
return maxThreshold; return maxThreshold;
if (RTT * 3 < minThreshold) if (RTT * 3 < minThreshold)
return minThreshold; return minThreshold;
return (CCTimeType) RTT * 3; return (CCTimeType) RTT * 3;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
void CCRakNetSlidingWindow::SetMTU(uint32_t bytes) void CCRakNetSlidingWindow::SetMTU(uint32_t bytes)
{ {
MAXIMUM_MTU_INCLUDING_UDP_HEADER=bytes; MAXIMUM_MTU_INCLUDING_UDP_HEADER=bytes;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
uint32_t CCRakNetSlidingWindow::GetMTU(void) const uint32_t CCRakNetSlidingWindow::GetMTU(void) const
{ {
return MAXIMUM_MTU_INCLUDING_UDP_HEADER; return MAXIMUM_MTU_INCLUDING_UDP_HEADER;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
BytesPerMicrosecond CCRakNetSlidingWindow::GetLocalReceiveRate(CCTimeType currentTime) const BytesPerMicrosecond CCRakNetSlidingWindow::GetLocalReceiveRate(CCTimeType currentTime) const
{ {
(void) currentTime; (void) currentTime;
return 0; // TODO return 0; // TODO
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
double CCRakNetSlidingWindow::GetRTT(void) const double CCRakNetSlidingWindow::GetRTT(void) const
{ {
if (RTT==UNSET_TIME_US) if (RTT==UNSET_TIME_US)
return 0.0; return 0.0;
return RTT; return RTT;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
bool CCRakNetSlidingWindow::GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b) bool CCRakNetSlidingWindow::GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b)
{ {
// a > b? // a > b?
const DatagramSequenceNumberType halfSpan =(DatagramSequenceNumberType) (((DatagramSequenceNumberType)(const uint32_t)-1)/(DatagramSequenceNumberType)2); const DatagramSequenceNumberType halfSpan =(DatagramSequenceNumberType) (((DatagramSequenceNumberType)(const uint32_t)-1)/(DatagramSequenceNumberType)2);
return b!=a && b-a>halfSpan; return b!=a && b-a>halfSpan;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
bool CCRakNetSlidingWindow::LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b) bool CCRakNetSlidingWindow::LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b)
{ {
// a < b? // a < b?
const DatagramSequenceNumberType halfSpan = ((DatagramSequenceNumberType)(const uint32_t)-1)/(DatagramSequenceNumberType)2; const DatagramSequenceNumberType halfSpan = ((DatagramSequenceNumberType)(const uint32_t)-1)/(DatagramSequenceNumberType)2;
return b!=a && b-a<halfSpan; return b!=a && b-a<halfSpan;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
uint64_t CCRakNetSlidingWindow::GetBytesPerSecondLimitByCongestionControl(void) const uint64_t CCRakNetSlidingWindow::GetBytesPerSecondLimitByCongestionControl(void) const
{ {
return 0; // TODO return 0; // TODO
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
CCTimeType CCRakNetSlidingWindow::GetSenderRTOForACK(void) const CCTimeType CCRakNetSlidingWindow::GetSenderRTOForACK(void) const
{ {
if (RTT==UNSET_TIME_US) if (RTT==UNSET_TIME_US)
return (CCTimeType) UNSET_TIME_US; return (CCTimeType) UNSET_TIME_US;
return (CCTimeType)(RTT + SYN); return (CCTimeType)(RTT + SYN);
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
bool CCRakNetSlidingWindow::IsInSlowStart(void) const bool CCRakNetSlidingWindow::IsInSlowStart(void) const
{ {
return cwnd <= ssThresh || ssThresh==0; return cwnd <= ssThresh || ssThresh==0;
} }
// ---------------------------------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------------
#endif #endif

View File

@@ -1,209 +1,209 @@
/* /*
http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html http://www.ssfnet.org/Exchange/tcp/tcpTutorialNotes.html
cwnd=max bytes allowed on wire at once cwnd=max bytes allowed on wire at once
Start: Start:
cwnd=mtu cwnd=mtu
ssthresh=unlimited ssthresh=unlimited
Slow start: Slow start:
On ack cwnd*=2 On ack cwnd*=2
congestion avoidance: congestion avoidance:
On ack during new period On ack during new period
cwnd+=mtu*mtu/cwnd cwnd+=mtu*mtu/cwnd
on loss or duplicate ack during period: on loss or duplicate ack during period:
sshtresh=cwnd/2 sshtresh=cwnd/2
cwnd=MTU cwnd=MTU
This reenters slow start This reenters slow start
If cwnd < ssthresh, then use slow start If cwnd < ssthresh, then use slow start
else use congestion avoidance else use congestion avoidance
*/ */
#include "RakNetDefines.h" #include "RakNetDefines.h"
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL==1 #if USE_SLIDING_WINDOW_CONGESTION_CONTROL==1
#ifndef __CONGESTION_CONTROL_SLIDING_WINDOW_H #ifndef __CONGESTION_CONTROL_SLIDING_WINDOW_H
#define __CONGESTION_CONTROL_SLIDING_WINDOW_H #define __CONGESTION_CONTROL_SLIDING_WINDOW_H
#include "NativeTypes.h" #include "NativeTypes.h"
#include "RakNetTime.h" #include "RakNetTime.h"
#include "RakNetTypes.h" #include "RakNetTypes.h"
#include "DS_Queue.h" #include "DS_Queue.h"
/// Sizeof an UDP header in byte /// Sizeof an UDP header in byte
#define UDP_HEADER_SIZE 28 #define UDP_HEADER_SIZE 28
#define CC_DEBUG_PRINTF_1(x) #define CC_DEBUG_PRINTF_1(x)
#define CC_DEBUG_PRINTF_2(x,y) #define CC_DEBUG_PRINTF_2(x,y)
#define CC_DEBUG_PRINTF_3(x,y,z) #define CC_DEBUG_PRINTF_3(x,y,z)
#define CC_DEBUG_PRINTF_4(x,y,z,a) #define CC_DEBUG_PRINTF_4(x,y,z,a)
#define CC_DEBUG_PRINTF_5(x,y,z,a,b) #define CC_DEBUG_PRINTF_5(x,y,z,a,b)
//#define CC_DEBUG_PRINTF_1(x) printf(x) //#define CC_DEBUG_PRINTF_1(x) printf(x)
//#define CC_DEBUG_PRINTF_2(x,y) printf(x,y) //#define CC_DEBUG_PRINTF_2(x,y) printf(x,y)
//#define CC_DEBUG_PRINTF_3(x,y,z) printf(x,y,z) //#define CC_DEBUG_PRINTF_3(x,y,z) printf(x,y,z)
//#define CC_DEBUG_PRINTF_4(x,y,z,a) printf(x,y,z,a) //#define CC_DEBUG_PRINTF_4(x,y,z,a) printf(x,y,z,a)
//#define CC_DEBUG_PRINTF_5(x,y,z,a,b) printf(x,y,z,a,b) //#define CC_DEBUG_PRINTF_5(x,y,z,a,b) printf(x,y,z,a,b)
/// Set to 4 if you are using the iPod Touch TG. See http://www.jenkinssoftware.com/forum/index.php?topic=2717.0 /// Set to 4 if you are using the iPod Touch TG. See http://www.jenkinssoftware.com/forum/index.php?topic=2717.0
#define CC_TIME_TYPE_BYTES 8 #define CC_TIME_TYPE_BYTES 8
typedef RakNet::TimeUS CCTimeType; typedef RakNet::TimeUS CCTimeType;
typedef RakNet::uint24_t DatagramSequenceNumberType; typedef RakNet::uint24_t DatagramSequenceNumberType;
typedef double BytesPerMicrosecond; typedef double BytesPerMicrosecond;
typedef double BytesPerSecond; typedef double BytesPerSecond;
typedef double MicrosecondsPerByte; typedef double MicrosecondsPerByte;
namespace RakNet namespace RakNet
{ {
class CCRakNetSlidingWindow class CCRakNetSlidingWindow
{ {
public: public:
CCRakNetSlidingWindow(); CCRakNetSlidingWindow();
~CCRakNetSlidingWindow(); ~CCRakNetSlidingWindow();
/// Reset all variables to their initial states, for a new connection /// Reset all variables to their initial states, for a new connection
void Init(CCTimeType curTime, uint32_t maxDatagramPayload); void Init(CCTimeType curTime, uint32_t maxDatagramPayload);
/// Update over time /// Update over time
void Update(CCTimeType curTime, bool hasDataToSendOrResend); void Update(CCTimeType curTime, bool hasDataToSendOrResend);
int GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend); int GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend);
int GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend); int GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend);
/// Acks do not have to be sent immediately. Instead, they can be buffered up such that groups of acks are sent at a time /// Acks do not have to be sent immediately. Instead, they can be buffered up such that groups of acks are sent at a time
/// This reduces overall bandwidth usage /// This reduces overall bandwidth usage
/// How long they can be buffered depends on the retransmit time of the sender /// How long they can be buffered depends on the retransmit time of the sender
/// Should call once per update tick, and send if needed /// Should call once per update tick, and send if needed
bool ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick); bool ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick);
/// Every data packet sent must contain a sequence number /// Every data packet sent must contain a sequence number
/// Call this function to get it. The sequence number is passed into OnGotPacketPair() /// Call this function to get it. The sequence number is passed into OnGotPacketPair()
DatagramSequenceNumberType GetAndIncrementNextDatagramSequenceNumber(void); DatagramSequenceNumberType GetAndIncrementNextDatagramSequenceNumber(void);
DatagramSequenceNumberType GetNextDatagramSequenceNumber(void); DatagramSequenceNumberType GetNextDatagramSequenceNumber(void);
/// Call this when you send packets /// Call this when you send packets
/// Every 15th and 16th packets should be sent as a packet pair if possible /// Every 15th and 16th packets should be sent as a packet pair if possible
/// When packets marked as a packet pair arrive, pass to OnGotPacketPair() /// When packets marked as a packet pair arrive, pass to OnGotPacketPair()
/// When any packets arrive, (additionally) pass to OnGotPacket /// When any packets arrive, (additionally) pass to OnGotPacket
/// Packets should contain our system time, so we can pass rtt to OnNonDuplicateAck() /// Packets should contain our system time, so we can pass rtt to OnNonDuplicateAck()
void OnSendBytes(CCTimeType curTime, uint32_t numBytes); void OnSendBytes(CCTimeType curTime, uint32_t numBytes);
/// Call this when you get a packet pair /// Call this when you get a packet pair
void OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime); void OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime);
/// Call this when you get a packet (including packet pairs) /// Call this when you get a packet (including packet pairs)
/// If the DatagramSequenceNumberType is out of order, skippedMessageCount will be non-zero /// If the DatagramSequenceNumberType is out of order, skippedMessageCount will be non-zero
/// In that case, send a NAK for every sequence number up to that count /// In that case, send a NAK for every sequence number up to that count
bool OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount); bool OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount);
/// Call when you get a NAK, with the sequence number of the lost message /// Call when you get a NAK, with the sequence number of the lost message
/// Affects the congestion control /// Affects the congestion control
void OnResend(CCTimeType curTime); void OnResend(CCTimeType curTime);
void OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber); void OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber);
/// Call this when an ACK arrives. /// Call this when an ACK arrives.
/// hasBAndAS are possibly written with the ack, see OnSendAck() /// hasBAndAS are possibly written with the ack, see OnSendAck()
/// B and AS are used in the calculations in UpdateWindowSizeAndAckOnAckPerSyn /// B and AS are used in the calculations in UpdateWindowSizeAndAckOnAckPerSyn
/// B and AS are updated at most once per SYN /// B and AS are updated at most once per SYN
void OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber ); void OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber );
void OnDuplicateAck( CCTimeType curTime, DatagramSequenceNumberType sequenceNumber ); void OnDuplicateAck( CCTimeType curTime, DatagramSequenceNumberType sequenceNumber );
/// Call when you send an ack, to see if the ack should have the B and AS parameters transmitted /// Call when you send an ack, to see if the ack should have the B and AS parameters transmitted
/// Call before calling OnSendAck() /// Call before calling OnSendAck()
void OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS); void OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS);
/// Call when we send an ack, to write B and AS if needed /// Call when we send an ack, to write B and AS if needed
/// B and AS are only written once per SYN, to prevent slow calculations /// B and AS are only written once per SYN, to prevent slow calculations
/// Also updates SND, the period between sends, since data is written out /// Also updates SND, the period between sends, since data is written out
/// Be sure to call OnSendAckGetBAndAS() before calling OnSendAck(), since whether you write it or not affects \a numBytes /// Be sure to call OnSendAckGetBAndAS() before calling OnSendAck(), since whether you write it or not affects \a numBytes
void OnSendAck(CCTimeType curTime, uint32_t numBytes); void OnSendAck(CCTimeType curTime, uint32_t numBytes);
/// Call when we send a NACK /// Call when we send a NACK
/// Also updates SND, the period between sends, since data is written out /// Also updates SND, the period between sends, since data is written out
void OnSendNACK(CCTimeType curTime, uint32_t numBytes); void OnSendNACK(CCTimeType curTime, uint32_t numBytes);
/// Retransmission time out for the sender /// Retransmission time out for the sender
/// If the time difference between when a message was last transmitted, and the current time is greater than RTO then packet is eligible for retransmission, pending congestion control /// If the time difference between when a message was last transmitted, and the current time is greater than RTO then packet is eligible for retransmission, pending congestion control
/// RTO = (RTT + 4 * RTTVar) + SYN /// RTO = (RTT + 4 * RTTVar) + SYN
/// If we have been continuously sending for the last RTO, and no ACK or NAK at all, SND*=2; /// If we have been continuously sending for the last RTO, and no ACK or NAK at all, SND*=2;
/// This is per message, which is different from UDT, but RakNet supports packetloss with continuing data where UDT is only RELIABLE_ORDERED /// This is per message, which is different from UDT, but RakNet supports packetloss with continuing data where UDT is only RELIABLE_ORDERED
/// Minimum value is 100 milliseconds /// Minimum value is 100 milliseconds
CCTimeType GetRTOForRetransmission(void) const; CCTimeType GetRTOForRetransmission(void) const;
/// Set the maximum amount of data that can be sent in one datagram /// Set the maximum amount of data that can be sent in one datagram
/// Default to MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE /// Default to MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE
void SetMTU(uint32_t bytes); void SetMTU(uint32_t bytes);
/// Return what was set by SetMTU() /// Return what was set by SetMTU()
uint32_t GetMTU(void) const; uint32_t GetMTU(void) const;
/// Query for statistics /// Query for statistics
BytesPerMicrosecond GetLocalSendRate(void) const {return 0;} BytesPerMicrosecond GetLocalSendRate(void) const {return 0;}
BytesPerMicrosecond GetLocalReceiveRate(CCTimeType currentTime) const; BytesPerMicrosecond GetLocalReceiveRate(CCTimeType currentTime) const;
BytesPerMicrosecond GetRemoveReceiveRate(void) const {return 0;} BytesPerMicrosecond GetRemoveReceiveRate(void) const {return 0;}
//BytesPerMicrosecond GetEstimatedBandwidth(void) const {return B;} //BytesPerMicrosecond GetEstimatedBandwidth(void) const {return B;}
BytesPerMicrosecond GetEstimatedBandwidth(void) const {return GetLinkCapacityBytesPerSecond()*1000000.0;} BytesPerMicrosecond GetEstimatedBandwidth(void) const {return GetLinkCapacityBytesPerSecond()*1000000.0;}
double GetLinkCapacityBytesPerSecond(void) const {return 0;} double GetLinkCapacityBytesPerSecond(void) const {return 0;}
/// Query for statistics /// Query for statistics
double GetRTT(void) const; double GetRTT(void) const;
bool GetIsInSlowStart(void) const {return IsInSlowStart();} bool GetIsInSlowStart(void) const {return IsInSlowStart();}
uint32_t GetCWNDLimit(void) const {return (uint32_t) 0;} uint32_t GetCWNDLimit(void) const {return (uint32_t) 0;}
/// Is a > b, accounting for variable overflow? /// Is a > b, accounting for variable overflow?
static bool GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b); static bool GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b);
/// Is a < b, accounting for variable overflow? /// Is a < b, accounting for variable overflow?
static bool LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b); static bool LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b);
// void SetTimeBetweenSendsLimit(unsigned int bitsPerSecond); // void SetTimeBetweenSendsLimit(unsigned int bitsPerSecond);
uint64_t GetBytesPerSecondLimitByCongestionControl(void) const; uint64_t GetBytesPerSecondLimitByCongestionControl(void) const;
protected: protected:
// Maximum amount of bytes that the user can send, e.g. the size of one full datagram // Maximum amount of bytes that the user can send, e.g. the size of one full datagram
uint32_t MAXIMUM_MTU_INCLUDING_UDP_HEADER; uint32_t MAXIMUM_MTU_INCLUDING_UDP_HEADER;
double RTT; double RTT;
double cwnd; // max bytes on wire double cwnd; // max bytes on wire
double ssThresh; // Threshhold between slow start and congestion avoidance double ssThresh; // Threshhold between slow start and congestion avoidance
/// When we get an ack, if oldestUnsentAck==0, set it to the current time /// When we get an ack, if oldestUnsentAck==0, set it to the current time
/// When we send out acks, set oldestUnsentAck to 0 /// When we send out acks, set oldestUnsentAck to 0
CCTimeType oldestUnsentAck; CCTimeType oldestUnsentAck;
CCTimeType GetSenderRTOForACK(void) const; CCTimeType GetSenderRTOForACK(void) const;
/// Every outgoing datagram is assigned a sequence number, which increments by 1 every assignment /// Every outgoing datagram is assigned a sequence number, which increments by 1 every assignment
DatagramSequenceNumberType nextDatagramSequenceNumber; DatagramSequenceNumberType nextDatagramSequenceNumber;
DatagramSequenceNumberType nextCongestionControlBlock; DatagramSequenceNumberType nextCongestionControlBlock;
bool backoffThisBlock, speedUpThisBlock; bool backoffThisBlock, speedUpThisBlock;
/// Track which datagram sequence numbers have arrived. /// Track which datagram sequence numbers have arrived.
/// If a sequence number is skipped, send a NAK for all skipped messages /// If a sequence number is skipped, send a NAK for all skipped messages
DatagramSequenceNumberType expectedNextSequenceNumber; DatagramSequenceNumberType expectedNextSequenceNumber;
bool _isContinuousSend; bool _isContinuousSend;
bool IsInSlowStart(void) const; bool IsInSlowStart(void) const;
}; };
} }
#endif #endif
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,394 +1,394 @@
#include "RakNetDefines.h" #include "RakNetDefines.h"
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL!=1 #if USE_SLIDING_WINDOW_CONGESTION_CONTROL!=1
#ifndef __CONGESTION_CONTROL_UDT_H #ifndef __CONGESTION_CONTROL_UDT_H
#define __CONGESTION_CONTROL_UDT_H #define __CONGESTION_CONTROL_UDT_H
#include "NativeTypes.h" #include "NativeTypes.h"
#include "RakNetTime.h" #include "RakNetTime.h"
#include "RakNetTypes.h" #include "RakNetTypes.h"
#include "DS_Queue.h" #include "DS_Queue.h"
/// Set to 4 if you are using the iPod Touch TG. See http://www.jenkinssoftware.com/forum/index.php?topic=2717.0 /// Set to 4 if you are using the iPod Touch TG. See http://www.jenkinssoftware.com/forum/index.php?topic=2717.0
#define CC_TIME_TYPE_BYTES 8 #define CC_TIME_TYPE_BYTES 8
namespace RakNet namespace RakNet
{ {
typedef uint64_t CCTimeType; typedef uint64_t CCTimeType;
typedef uint24_t DatagramSequenceNumberType; typedef uint24_t DatagramSequenceNumberType;
typedef double BytesPerMicrosecond; typedef double BytesPerMicrosecond;
typedef double BytesPerSecond; typedef double BytesPerSecond;
typedef double MicrosecondsPerByte; typedef double MicrosecondsPerByte;
/// CC_RAKNET_UDT_PACKET_HISTORY_LENGTH should be a power of 2 for the writeIndex variables to wrap properly /// CC_RAKNET_UDT_PACKET_HISTORY_LENGTH should be a power of 2 for the writeIndex variables to wrap properly
#define CC_RAKNET_UDT_PACKET_HISTORY_LENGTH 64 #define CC_RAKNET_UDT_PACKET_HISTORY_LENGTH 64
#define RTT_HISTORY_LENGTH 64 #define RTT_HISTORY_LENGTH 64
/// Sizeof an UDP header in byte /// Sizeof an UDP header in byte
#define UDP_HEADER_SIZE 28 #define UDP_HEADER_SIZE 28
#define CC_DEBUG_PRINTF_1(x) #define CC_DEBUG_PRINTF_1(x)
#define CC_DEBUG_PRINTF_2(x,y) #define CC_DEBUG_PRINTF_2(x,y)
#define CC_DEBUG_PRINTF_3(x,y,z) #define CC_DEBUG_PRINTF_3(x,y,z)
#define CC_DEBUG_PRINTF_4(x,y,z,a) #define CC_DEBUG_PRINTF_4(x,y,z,a)
#define CC_DEBUG_PRINTF_5(x,y,z,a,b) #define CC_DEBUG_PRINTF_5(x,y,z,a,b)
//#define CC_DEBUG_PRINTF_1(x) printf(x) //#define CC_DEBUG_PRINTF_1(x) printf(x)
//#define CC_DEBUG_PRINTF_2(x,y) printf(x,y) //#define CC_DEBUG_PRINTF_2(x,y) printf(x,y)
//#define CC_DEBUG_PRINTF_3(x,y,z) printf(x,y,z) //#define CC_DEBUG_PRINTF_3(x,y,z) printf(x,y,z)
//#define CC_DEBUG_PRINTF_4(x,y,z,a) printf(x,y,z,a) //#define CC_DEBUG_PRINTF_4(x,y,z,a) printf(x,y,z,a)
//#define CC_DEBUG_PRINTF_5(x,y,z,a,b) printf(x,y,z,a,b) //#define CC_DEBUG_PRINTF_5(x,y,z,a,b) printf(x,y,z,a,b)
/// \brief Encapsulates UDT congestion control, as used by RakNet /// \brief Encapsulates UDT congestion control, as used by RakNet
/// Requirements: /// Requirements:
/// <OL> /// <OL>
/// <LI>Each datagram is no more than MAXIMUM_MTU_SIZE, after accounting for the UDP header /// <LI>Each datagram is no more than MAXIMUM_MTU_SIZE, after accounting for the UDP header
/// <LI>Each datagram containing a user message has a sequence number which is set after calling OnSendBytes(). Set it by calling GetAndIncrementNextDatagramSequenceNumber() /// <LI>Each datagram containing a user message has a sequence number which is set after calling OnSendBytes(). Set it by calling GetAndIncrementNextDatagramSequenceNumber()
/// <LI>System is designed to be used from a single thread. /// <LI>System is designed to be used from a single thread.
/// <LI>Each packet should have a timeout time based on GetSenderRTOForACK(). If this time elapses, add the packet to the head of the send list for retransmission. /// <LI>Each packet should have a timeout time based on GetSenderRTOForACK(). If this time elapses, add the packet to the head of the send list for retransmission.
/// </OL> /// </OL>
/// ///
/// Recommended: /// Recommended:
/// <OL> /// <OL>
/// <LI>Call sendto in its own thread. This takes a significant amount of time in high speed networks. /// <LI>Call sendto in its own thread. This takes a significant amount of time in high speed networks.
/// </OL> /// </OL>
/// ///
/// Algorithm: /// Algorithm:
/// <OL> /// <OL>
/// <LI>On a new connection, call Init() /// <LI>On a new connection, call Init()
/// <LI>On a periodic interval (SYN time is the best) call Update(). Also call ShouldSendACKs(), and send buffered ACKS if it returns true. /// <LI>On a periodic interval (SYN time is the best) call Update(). Also call ShouldSendACKs(), and send buffered ACKS if it returns true.
/// <LI>Call OnSendAck() when sending acks. /// <LI>Call OnSendAck() when sending acks.
/// <LI>When you want to send or resend data, call GetNumberOfBytesToSend(). It will return you enough bytes to keep you busy for \a estimatedTimeToNextTick. You can send more than this to fill out a datagram, or to send packet pairs /// <LI>When you want to send or resend data, call GetNumberOfBytesToSend(). It will return you enough bytes to keep you busy for \a estimatedTimeToNextTick. You can send more than this to fill out a datagram, or to send packet pairs
/// <LI>Call OnSendBytes() when sending datagrams. /// <LI>Call OnSendBytes() when sending datagrams.
/// <LI>When data arrives, record the sequence number and buffer an ACK for it, to be sent from Update() if ShouldSendACKs() returns true /// <LI>When data arrives, record the sequence number and buffer an ACK for it, to be sent from Update() if ShouldSendACKs() returns true
/// <LI>Every 16 packets that you send, send two of them back to back (a packet pair) as long as both packets are the same size. If you don't have two packets the same size, it is fine to defer this until you do. /// <LI>Every 16 packets that you send, send two of them back to back (a packet pair) as long as both packets are the same size. If you don't have two packets the same size, it is fine to defer this until you do.
/// <LI>When you get a packet, call OnGotPacket(). If the packet is also either of a packet pair, call OnGotPacketPair() /// <LI>When you get a packet, call OnGotPacket(). If the packet is also either of a packet pair, call OnGotPacketPair()
/// <LI>If you get a packet, and the sequence number is not 1 + the last sequence number, send a NAK. On the remote system, call OnNAK() and resend that message. /// <LI>If you get a packet, and the sequence number is not 1 + the last sequence number, send a NAK. On the remote system, call OnNAK() and resend that message.
/// <LI>If you get an ACK, remove that message from retransmission. Call OnNonDuplicateAck(). /// <LI>If you get an ACK, remove that message from retransmission. Call OnNonDuplicateAck().
/// <LI>If a message is not ACKed for GetRTOForRetransmission(), resend it. /// <LI>If a message is not ACKed for GetRTOForRetransmission(), resend it.
/// </OL> /// </OL>
class CCRakNetUDT class CCRakNetUDT
{ {
public: public:
CCRakNetUDT(); CCRakNetUDT();
~CCRakNetUDT(); ~CCRakNetUDT();
/// Reset all variables to their initial states, for a new connection /// Reset all variables to their initial states, for a new connection
void Init(CCTimeType curTime, uint32_t maxDatagramPayload); void Init(CCTimeType curTime, uint32_t maxDatagramPayload);
/// Update over time /// Update over time
void Update(CCTimeType curTime, bool hasDataToSendOrResend); void Update(CCTimeType curTime, bool hasDataToSendOrResend);
int GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend); int GetRetransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend);
int GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend); int GetTransmissionBandwidth(CCTimeType curTime, CCTimeType timeSinceLastTick, uint32_t unacknowledgedBytes, bool isContinuousSend);
/// Acks do not have to be sent immediately. Instead, they can be buffered up such that groups of acks are sent at a time /// Acks do not have to be sent immediately. Instead, they can be buffered up such that groups of acks are sent at a time
/// This reduces overall bandwidth usage /// This reduces overall bandwidth usage
/// How long they can be buffered depends on the retransmit time of the sender /// How long they can be buffered depends on the retransmit time of the sender
/// Should call once per update tick, and send if needed /// Should call once per update tick, and send if needed
bool ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick); bool ShouldSendACKs(CCTimeType curTime, CCTimeType estimatedTimeToNextTick);
/// Every data packet sent must contain a sequence number /// Every data packet sent must contain a sequence number
/// Call this function to get it. The sequence number is passed into OnGotPacketPair() /// Call this function to get it. The sequence number is passed into OnGotPacketPair()
DatagramSequenceNumberType GetAndIncrementNextDatagramSequenceNumber(void); DatagramSequenceNumberType GetAndIncrementNextDatagramSequenceNumber(void);
DatagramSequenceNumberType GetNextDatagramSequenceNumber(void); DatagramSequenceNumberType GetNextDatagramSequenceNumber(void);
/// Call this when you send packets /// Call this when you send packets
/// Every 15th and 16th packets should be sent as a packet pair if possible /// Every 15th and 16th packets should be sent as a packet pair if possible
/// When packets marked as a packet pair arrive, pass to OnGotPacketPair() /// When packets marked as a packet pair arrive, pass to OnGotPacketPair()
/// When any packets arrive, (additionally) pass to OnGotPacket /// When any packets arrive, (additionally) pass to OnGotPacket
/// Packets should contain our system time, so we can pass rtt to OnNonDuplicateAck() /// Packets should contain our system time, so we can pass rtt to OnNonDuplicateAck()
void OnSendBytes(CCTimeType curTime, uint32_t numBytes); void OnSendBytes(CCTimeType curTime, uint32_t numBytes);
/// Call this when you get a packet pair /// Call this when you get a packet pair
void OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime); void OnGotPacketPair(DatagramSequenceNumberType datagramSequenceNumber, uint32_t sizeInBytes, CCTimeType curTime);
/// Call this when you get a packet (including packet pairs) /// Call this when you get a packet (including packet pairs)
/// If the DatagramSequenceNumberType is out of order, skippedMessageCount will be non-zero /// If the DatagramSequenceNumberType is out of order, skippedMessageCount will be non-zero
/// In that case, send a NAK for every sequence number up to that count /// In that case, send a NAK for every sequence number up to that count
bool OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount); bool OnGotPacket(DatagramSequenceNumberType datagramSequenceNumber, bool isContinuousSend, CCTimeType curTime, uint32_t sizeInBytes, uint32_t *skippedMessageCount);
/// Call when you get a NAK, with the sequence number of the lost message /// Call when you get a NAK, with the sequence number of the lost message
/// Affects the congestion control /// Affects the congestion control
void OnResend(CCTimeType curTime); void OnResend(CCTimeType curTime);
void OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber); void OnNAK(CCTimeType curTime, DatagramSequenceNumberType nakSequenceNumber);
/// Call this when an ACK arrives. /// Call this when an ACK arrives.
/// hasBAndAS are possibly written with the ack, see OnSendAck() /// hasBAndAS are possibly written with the ack, see OnSendAck()
/// B and AS are used in the calculations in UpdateWindowSizeAndAckOnAckPerSyn /// B and AS are used in the calculations in UpdateWindowSizeAndAckOnAckPerSyn
/// B and AS are updated at most once per SYN /// B and AS are updated at most once per SYN
void OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber ); void OnAck(CCTimeType curTime, CCTimeType rtt, bool hasBAndAS, BytesPerMicrosecond _B, BytesPerMicrosecond _AS, double totalUserDataBytesAcked, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber );
void OnDuplicateAck( CCTimeType curTime, DatagramSequenceNumberType sequenceNumber ) {} void OnDuplicateAck( CCTimeType curTime, DatagramSequenceNumberType sequenceNumber ) {}
/// Call when you send an ack, to see if the ack should have the B and AS parameters transmitted /// Call when you send an ack, to see if the ack should have the B and AS parameters transmitted
/// Call before calling OnSendAck() /// Call before calling OnSendAck()
void OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS); void OnSendAckGetBAndAS(CCTimeType curTime, bool *hasBAndAS, BytesPerMicrosecond *_B, BytesPerMicrosecond *_AS);
/// Call when we send an ack, to write B and AS if needed /// Call when we send an ack, to write B and AS if needed
/// B and AS are only written once per SYN, to prevent slow calculations /// B and AS are only written once per SYN, to prevent slow calculations
/// Also updates SND, the period between sends, since data is written out /// Also updates SND, the period between sends, since data is written out
/// Be sure to call OnSendAckGetBAndAS() before calling OnSendAck(), since whether you write it or not affects \a numBytes /// Be sure to call OnSendAckGetBAndAS() before calling OnSendAck(), since whether you write it or not affects \a numBytes
void OnSendAck(CCTimeType curTime, uint32_t numBytes); void OnSendAck(CCTimeType curTime, uint32_t numBytes);
/// Call when we send a NACK /// Call when we send a NACK
/// Also updates SND, the period between sends, since data is written out /// Also updates SND, the period between sends, since data is written out
void OnSendNACK(CCTimeType curTime, uint32_t numBytes); void OnSendNACK(CCTimeType curTime, uint32_t numBytes);
/// Retransmission time out for the sender /// Retransmission time out for the sender
/// If the time difference between when a message was last transmitted, and the current time is greater than RTO then packet is eligible for retransmission, pending congestion control /// If the time difference between when a message was last transmitted, and the current time is greater than RTO then packet is eligible for retransmission, pending congestion control
/// RTO = (RTT + 4 * RTTVar) + SYN /// RTO = (RTT + 4 * RTTVar) + SYN
/// If we have been continuously sending for the last RTO, and no ACK or NAK at all, SND*=2; /// If we have been continuously sending for the last RTO, and no ACK or NAK at all, SND*=2;
/// This is per message, which is different from UDT, but RakNet supports packetloss with continuing data where UDT is only RELIABLE_ORDERED /// This is per message, which is different from UDT, but RakNet supports packetloss with continuing data where UDT is only RELIABLE_ORDERED
/// Minimum value is 100 milliseconds /// Minimum value is 100 milliseconds
CCTimeType GetRTOForRetransmission(void) const; CCTimeType GetRTOForRetransmission(void) const;
/// Set the maximum amount of data that can be sent in one datagram /// Set the maximum amount of data that can be sent in one datagram
/// Default to MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE /// Default to MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE
void SetMTU(uint32_t bytes); void SetMTU(uint32_t bytes);
/// Return what was set by SetMTU() /// Return what was set by SetMTU()
uint32_t GetMTU(void) const; uint32_t GetMTU(void) const;
/// Query for statistics /// Query for statistics
BytesPerMicrosecond GetLocalSendRate(void) const {return 1.0 / SND;} BytesPerMicrosecond GetLocalSendRate(void) const {return 1.0 / SND;}
BytesPerMicrosecond GetLocalReceiveRate(CCTimeType currentTime) const; BytesPerMicrosecond GetLocalReceiveRate(CCTimeType currentTime) const;
BytesPerMicrosecond GetRemoveReceiveRate(void) const {return AS;} BytesPerMicrosecond GetRemoveReceiveRate(void) const {return AS;}
//BytesPerMicrosecond GetEstimatedBandwidth(void) const {return B;} //BytesPerMicrosecond GetEstimatedBandwidth(void) const {return B;}
BytesPerMicrosecond GetEstimatedBandwidth(void) const {return GetLinkCapacityBytesPerSecond()*1000000.0;} BytesPerMicrosecond GetEstimatedBandwidth(void) const {return GetLinkCapacityBytesPerSecond()*1000000.0;}
double GetLinkCapacityBytesPerSecond(void) const {return estimatedLinkCapacityBytesPerSecond;}; double GetLinkCapacityBytesPerSecond(void) const {return estimatedLinkCapacityBytesPerSecond;};
/// Query for statistics /// Query for statistics
double GetRTT(void) const; double GetRTT(void) const;
bool GetIsInSlowStart(void) const {return isInSlowStart;} bool GetIsInSlowStart(void) const {return isInSlowStart;}
uint32_t GetCWNDLimit(void) const {return (uint32_t) (CWND*MAXIMUM_MTU_INCLUDING_UDP_HEADER);} uint32_t GetCWNDLimit(void) const {return (uint32_t) (CWND*MAXIMUM_MTU_INCLUDING_UDP_HEADER);}
/// Is a > b, accounting for variable overflow? /// Is a > b, accounting for variable overflow?
static bool GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b); static bool GreaterThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b);
/// Is a < b, accounting for variable overflow? /// Is a < b, accounting for variable overflow?
static bool LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b); static bool LessThan(DatagramSequenceNumberType a, DatagramSequenceNumberType b);
// void SetTimeBetweenSendsLimit(unsigned int bitsPerSecond); // void SetTimeBetweenSendsLimit(unsigned int bitsPerSecond);
uint64_t GetBytesPerSecondLimitByCongestionControl(void) const; uint64_t GetBytesPerSecondLimitByCongestionControl(void) const;
protected: protected:
// --------------------------- PROTECTED VARIABLES --------------------------- // --------------------------- PROTECTED VARIABLES ---------------------------
/// time interval between bytes, in microseconds. /// time interval between bytes, in microseconds.
/// Only used when slowStart==false /// Only used when slowStart==false
/// Increased over time as we continually get messages /// Increased over time as we continually get messages
/// Decreased on NAK and timeout /// Decreased on NAK and timeout
/// Starts at 0 (invalid) /// Starts at 0 (invalid)
MicrosecondsPerByte SND; MicrosecondsPerByte SND;
/// Supportive window mechanism, controlling the maximum number of in-flight packets /// Supportive window mechanism, controlling the maximum number of in-flight packets
/// Used both during and after slow-start, but primarily during slow-start /// Used both during and after slow-start, but primarily during slow-start
/// Starts at 2, which is also the low threshhold /// Starts at 2, which is also the low threshhold
/// Max is the socket receive buffer / MTU /// Max is the socket receive buffer / MTU
/// CWND = AS * (RTT + SYN) + 16 /// CWND = AS * (RTT + SYN) + 16
double CWND; double CWND;
/// When we do an update process on the SYN interval, nextSYNUpdate is set to the next time we should update /// When we do an update process on the SYN interval, nextSYNUpdate is set to the next time we should update
/// Normally this is nextSYNUpdate+=SYN, in order to update on a consistent schedule /// Normally this is nextSYNUpdate+=SYN, in order to update on a consistent schedule
/// However, if this would result in an immediate update yet again, it is set to SYN microseconds past the current time (in case the thread did not update for a long time) /// However, if this would result in an immediate update yet again, it is set to SYN microseconds past the current time (in case the thread did not update for a long time)
CCTimeType nextSYNUpdate; CCTimeType nextSYNUpdate;
/// Index into packetPairRecieptHistory where we will next write /// Index into packetPairRecieptHistory where we will next write
/// The history is always full (starting with default values) so no read index is needed /// The history is always full (starting with default values) so no read index is needed
int packetPairRecieptHistoryWriteIndex; int packetPairRecieptHistoryWriteIndex;
/// Sent to the sender by the receiver from packetPairRecieptHistory whenever a back to back packet arrives on the receiver /// Sent to the sender by the receiver from packetPairRecieptHistory whenever a back to back packet arrives on the receiver
/// Updated by B = B * .875 + incomingB * .125 /// Updated by B = B * .875 + incomingB * .125
//BytesPerMicrosecond B; //BytesPerMicrosecond B;
/// Running round trip time (ping*2) /// Running round trip time (ping*2)
/// Only sender needs to know this /// Only sender needs to know this
/// Initialized to UNSET /// Initialized to UNSET
/// Set to rtt on first calculation /// Set to rtt on first calculation
/// Updated gradually by RTT = RTT * 0.875 + rtt * 0.125 /// Updated gradually by RTT = RTT * 0.875 + rtt * 0.125
double RTT; double RTT;
/// Round trip time variance /// Round trip time variance
/// Only sender needs to know this /// Only sender needs to know this
/// Initialized to UNSET /// Initialized to UNSET
/// Set to rtt on first calculation /// Set to rtt on first calculation
// double RTTVar; // double RTTVar;
/// Update: Use min/max, RTTVar follows current variance too closely resulting in packetloss /// Update: Use min/max, RTTVar follows current variance too closely resulting in packetloss
double minRTT, maxRTT; double minRTT, maxRTT;
/// Used to calculate packet arrival rate (in UDT) but data arrival rate (in RakNet, where not all datagrams are the same size) /// Used to calculate packet arrival rate (in UDT) but data arrival rate (in RakNet, where not all datagrams are the same size)
/// Filter is used to cull lowest half of values for bytesPerMicrosecond, to discount spikes and inactivity /// Filter is used to cull lowest half of values for bytesPerMicrosecond, to discount spikes and inactivity
/// Referred to in the documentation as AS, data arrival rate /// Referred to in the documentation as AS, data arrival rate
/// AS is sent to the sender and calculated every 10th ack /// AS is sent to the sender and calculated every 10th ack
/// Each node represents (curTime-lastPacketArrivalTime)/bytes /// Each node represents (curTime-lastPacketArrivalTime)/bytes
/// Used with ReceiverCalculateDataArrivalRate(); /// Used with ReceiverCalculateDataArrivalRate();
BytesPerMicrosecond packetArrivalHistory[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH]; BytesPerMicrosecond packetArrivalHistory[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH];
BytesPerMicrosecond packetArrivalHistoryContinuousGaps[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH]; BytesPerMicrosecond packetArrivalHistoryContinuousGaps[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH];
unsigned char packetArrivalHistoryContinuousGapsIndex; unsigned char packetArrivalHistoryContinuousGapsIndex;
uint64_t continuousBytesReceived; uint64_t continuousBytesReceived;
CCTimeType continuousBytesReceivedStartTime; CCTimeType continuousBytesReceivedStartTime;
unsigned int packetArrivalHistoryWriteCount; unsigned int packetArrivalHistoryWriteCount;
/// Index into packetArrivalHistory where we will next write /// Index into packetArrivalHistory where we will next write
/// The history is always full (starting with default values) so no read index is needed /// The history is always full (starting with default values) so no read index is needed
int packetArrivalHistoryWriteIndex; int packetArrivalHistoryWriteIndex;
/// Tracks the time the last packet that arrived, so BytesPerMicrosecond can be calculated for packetArrivalHistory when a new packet arrives /// Tracks the time the last packet that arrived, so BytesPerMicrosecond can be calculated for packetArrivalHistory when a new packet arrives
CCTimeType lastPacketArrivalTime; CCTimeType lastPacketArrivalTime;
/// Data arrival rate from the sender to the receiver, as told to us by the receiver /// Data arrival rate from the sender to the receiver, as told to us by the receiver
/// Used to calculate initial sending rate when slow start stops /// Used to calculate initial sending rate when slow start stops
BytesPerMicrosecond AS; BytesPerMicrosecond AS;
/// When the receiver last calculated and send B and AS, from packetArrivalHistory and packetPairRecieptHistory /// When the receiver last calculated and send B and AS, from packetArrivalHistory and packetPairRecieptHistory
/// Used to prevent it from being calculated and send too frequently, as they are slow operations /// Used to prevent it from being calculated and send too frequently, as they are slow operations
CCTimeType lastTransmitOfBAndAS; CCTimeType lastTransmitOfBAndAS;
/// New connections start in slow start /// New connections start in slow start
/// During slow start, SND is not used, only CWND /// During slow start, SND is not used, only CWND
/// Slow start ends when we get a NAK, or the maximum size of CWND is reached /// Slow start ends when we get a NAK, or the maximum size of CWND is reached
/// SND is initialized to the inverse of the receiver's packet arrival rate when slow start ends /// SND is initialized to the inverse of the receiver's packet arrival rate when slow start ends
bool isInSlowStart; bool isInSlowStart;
/// How many NAKs arrived this congestion period /// How many NAKs arrived this congestion period
/// Initialized to 1 when the congestion period starts /// Initialized to 1 when the congestion period starts
uint32_t NAKCount; uint32_t NAKCount;
/// How many NAKs do you get on average during a congestion period? /// How many NAKs do you get on average during a congestion period?
/// Starts at 1 /// Starts at 1
/// Used to generate a random number, DecRandom, between 1 and AvgNAKNum /// Used to generate a random number, DecRandom, between 1 and AvgNAKNum
uint32_t AvgNAKNum; uint32_t AvgNAKNum;
/// How many times we have decremented SND this congestion period. Used to limit the number of decrements to 5 /// How many times we have decremented SND this congestion period. Used to limit the number of decrements to 5
uint32_t DecCount; uint32_t DecCount;
/// Every DecInterval NAKs per congestion period, we decrease the send rate /// Every DecInterval NAKs per congestion period, we decrease the send rate
uint32_t DecInterval; uint32_t DecInterval;
/// Every outgoing datagram is assigned a sequence number, which increments by 1 every assignment /// Every outgoing datagram is assigned a sequence number, which increments by 1 every assignment
DatagramSequenceNumberType nextDatagramSequenceNumber; DatagramSequenceNumberType nextDatagramSequenceNumber;
/// If a packet is marked as a packet pair, lastPacketPairPacketArrivalTime is set to the time it arrives /// If a packet is marked as a packet pair, lastPacketPairPacketArrivalTime is set to the time it arrives
/// This is used so when the 2nd packet of the pair arrives, we can calculate the time interval between the two /// This is used so when the 2nd packet of the pair arrives, we can calculate the time interval between the two
CCTimeType lastPacketPairPacketArrivalTime; CCTimeType lastPacketPairPacketArrivalTime;
/// If a packet is marked as a packet pair, lastPacketPairSequenceNumber is checked to see if the last packet we got /// If a packet is marked as a packet pair, lastPacketPairSequenceNumber is checked to see if the last packet we got
/// was the packet immediately before the one that arrived /// was the packet immediately before the one that arrived
/// If so, we can use lastPacketPairPacketArrivalTime to get the time between the two packets, and thus estimate the link capacity /// If so, we can use lastPacketPairPacketArrivalTime to get the time between the two packets, and thus estimate the link capacity
/// Initialized to -1, so the first packet of a packet pair won't be treated as the second /// Initialized to -1, so the first packet of a packet pair won't be treated as the second
DatagramSequenceNumberType lastPacketPairSequenceNumber; DatagramSequenceNumberType lastPacketPairSequenceNumber;
/// Used to cap UpdateWindowSizeAndAckOnAckPerSyn() to once speed increase per SYN /// Used to cap UpdateWindowSizeAndAckOnAckPerSyn() to once speed increase per SYN
/// This is to prevent speeding up faster than congestion control can compensate for /// This is to prevent speeding up faster than congestion control can compensate for
CCTimeType lastUpdateWindowSizeAndAck; CCTimeType lastUpdateWindowSizeAndAck;
/// Every time SND is halved due to timeout, the RTO is increased /// Every time SND is halved due to timeout, the RTO is increased
/// This is to prevent massive retransmissions to an unresponsive system /// This is to prevent massive retransmissions to an unresponsive system
/// Reset on any data arriving /// Reset on any data arriving
double ExpCount; double ExpCount;
/// Total number of user data bytes sent /// Total number of user data bytes sent
/// Used to adjust the window size, on ACK, during slow start /// Used to adjust the window size, on ACK, during slow start
uint64_t totalUserDataBytesSent; uint64_t totalUserDataBytesSent;
/// When we get an ack, if oldestUnsentAck==0, set it to the current time /// When we get an ack, if oldestUnsentAck==0, set it to the current time
/// When we send out acks, set oldestUnsentAck to 0 /// When we send out acks, set oldestUnsentAck to 0
CCTimeType oldestUnsentAck; CCTimeType oldestUnsentAck;
// Maximum amount of bytes that the user can send, e.g. the size of one full datagram // Maximum amount of bytes that the user can send, e.g. the size of one full datagram
uint32_t MAXIMUM_MTU_INCLUDING_UDP_HEADER; uint32_t MAXIMUM_MTU_INCLUDING_UDP_HEADER;
// Max window size // Max window size
double CWND_MAX_THRESHOLD; double CWND_MAX_THRESHOLD;
/// Track which datagram sequence numbers have arrived. /// Track which datagram sequence numbers have arrived.
/// If a sequence number is skipped, send a NAK for all skipped messages /// If a sequence number is skipped, send a NAK for all skipped messages
DatagramSequenceNumberType expectedNextSequenceNumber; DatagramSequenceNumberType expectedNextSequenceNumber;
// How many times have we sent B and AS? Used to force it to send at least CC_RAKNET_UDT_PACKET_HISTORY_LENGTH times // How many times have we sent B and AS? Used to force it to send at least CC_RAKNET_UDT_PACKET_HISTORY_LENGTH times
// Otherwise, the default values in the array generate inaccuracy // Otherwise, the default values in the array generate inaccuracy
uint32_t sendBAndASCount; uint32_t sendBAndASCount;
/// Most recent values read into the corresponding lists /// Most recent values read into the corresponding lists
/// Used during the beginning of a connection, when the median filter is still inaccurate /// Used during the beginning of a connection, when the median filter is still inaccurate
BytesPerMicrosecond mostRecentPacketArrivalHistory; BytesPerMicrosecond mostRecentPacketArrivalHistory;
bool hasWrittenToPacketPairReceiptHistory; bool hasWrittenToPacketPairReceiptHistory;
// uint32_t rttHistory[RTT_HISTORY_LENGTH]; // uint32_t rttHistory[RTT_HISTORY_LENGTH];
// uint32_t rttHistoryIndex; // uint32_t rttHistoryIndex;
// uint32_t rttHistoryWriteCount; // uint32_t rttHistoryWriteCount;
// uint32_t rttSum, rttLow; // uint32_t rttSum, rttLow;
// CCTimeType lastSndUpdateTime; // CCTimeType lastSndUpdateTime;
double estimatedLinkCapacityBytesPerSecond; double estimatedLinkCapacityBytesPerSecond;
// --------------------------- PROTECTED METHODS --------------------------- // --------------------------- PROTECTED METHODS ---------------------------
/// Update nextSYNUpdate by SYN, or the same amount past the current time if no updates have occurred for a long time /// Update nextSYNUpdate by SYN, or the same amount past the current time if no updates have occurred for a long time
void SetNextSYNUpdate(CCTimeType currentTime); void SetNextSYNUpdate(CCTimeType currentTime);
/// Returns the rate of data arrival, based on packets arriving on the sender. /// Returns the rate of data arrival, based on packets arriving on the sender.
BytesPerMicrosecond ReceiverCalculateDataArrivalRate(CCTimeType curTime) const; BytesPerMicrosecond ReceiverCalculateDataArrivalRate(CCTimeType curTime) const;
/// Returns the median of the data arrival rate /// Returns the median of the data arrival rate
BytesPerMicrosecond ReceiverCalculateDataArrivalRateMedian(void) const; BytesPerMicrosecond ReceiverCalculateDataArrivalRateMedian(void) const;
/// Calculates the median an array of BytesPerMicrosecond /// Calculates the median an array of BytesPerMicrosecond
static BytesPerMicrosecond CalculateListMedianRecursive(const BytesPerMicrosecond inputList[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH], int inputListLength, int lessThanSum, int greaterThanSum); static BytesPerMicrosecond CalculateListMedianRecursive(const BytesPerMicrosecond inputList[CC_RAKNET_UDT_PACKET_HISTORY_LENGTH], int inputListLength, int lessThanSum, int greaterThanSum);
// static uint32_t CalculateListMedianRecursive(const uint32_t inputList[RTT_HISTORY_LENGTH], int inputListLength, int lessThanSum, int greaterThanSum); // static uint32_t CalculateListMedianRecursive(const uint32_t inputList[RTT_HISTORY_LENGTH], int inputListLength, int lessThanSum, int greaterThanSum);
/// Same as GetRTOForRetransmission, but does not factor in ExpCount /// Same as GetRTOForRetransmission, but does not factor in ExpCount
/// This is because the receiver does not know ExpCount for the sender, and even if it did, acks shouldn't be delayed for this reason /// This is because the receiver does not know ExpCount for the sender, and even if it did, acks shouldn't be delayed for this reason
CCTimeType GetSenderRTOForACK(void) const; CCTimeType GetSenderRTOForACK(void) const;
/// Stop slow start, and enter normal transfer rate /// Stop slow start, and enter normal transfer rate
void EndSlowStart(void); void EndSlowStart(void);
/// Does the named conversion /// Does the named conversion
inline double BytesPerMicrosecondToPacketsPerMillisecond(BytesPerMicrosecond in); inline double BytesPerMicrosecondToPacketsPerMillisecond(BytesPerMicrosecond in);
/// Update the round trip time, from ACK or ACK2 /// Update the round trip time, from ACK or ACK2
//void UpdateRTT(CCTimeType rtt); //void UpdateRTT(CCTimeType rtt);
/// Update the corresponding variables pre-slow start /// Update the corresponding variables pre-slow start
void UpdateWindowSizeAndAckOnAckPreSlowStart(double totalUserDataBytesAcked); void UpdateWindowSizeAndAckOnAckPreSlowStart(double totalUserDataBytesAcked);
/// Update the corresponding variables post-slow start /// Update the corresponding variables post-slow start
void UpdateWindowSizeAndAckOnAckPerSyn(CCTimeType curTime, CCTimeType rtt, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber); void UpdateWindowSizeAndAckOnAckPerSyn(CCTimeType curTime, CCTimeType rtt, bool isContinuousSend, DatagramSequenceNumberType sequenceNumber);
/// Sets halveSNDOnNoDataTime to the future, and also resets ExpCount, which is used to multiple the RTO on no data arriving at all /// Sets halveSNDOnNoDataTime to the future, and also resets ExpCount, which is used to multiple the RTO on no data arriving at all
void ResetOnDataArrivalHalveSNDOnNoDataTime(CCTimeType curTime); void ResetOnDataArrivalHalveSNDOnNoDataTime(CCTimeType curTime);
// Init array // Init array
void InitPacketArrivalHistory(void); void InitPacketArrivalHistory(void);
// Printf // Printf
void PrintLowBandwidthWarning(void); void PrintLowBandwidthWarning(void);
// Bug: SND can sometimes get super high - have seen 11693 // Bug: SND can sometimes get super high - have seen 11693
void CapMinSnd(const char *file, int line); void CapMinSnd(const char *file, int line);
void DecreaseTimeBetweenSends(void); void DecreaseTimeBetweenSends(void);
void IncreaseTimeBetweenSends(void); void IncreaseTimeBetweenSends(void);
int bytesCanSendThisTick; int bytesCanSendThisTick;
CCTimeType lastRttOnIncreaseSendRate; CCTimeType lastRttOnIncreaseSendRate;
CCTimeType lastRtt; CCTimeType lastRtt;
DatagramSequenceNumberType nextCongestionControlBlock; DatagramSequenceNumberType nextCongestionControlBlock;
bool hadPacketlossThisBlock; bool hadPacketlossThisBlock;
DataStructures::Queue<CCTimeType> pingsLastInterval; DataStructures::Queue<CCTimeType> pingsLastInterval;
}; };
} }
#endif #endif
#endif #endif

View File

@@ -1,97 +1,97 @@
/** /**
* @file * @file
* @brief CheckSum implementation from http://www.flounder.com/checksum.htm * @brief CheckSum implementation from http://www.flounder.com/checksum.htm
* *
*/ */
#include "CheckSum.h" #include "CheckSum.h"
/**************************************************************************** /****************************************************************************
* CheckSum::add * CheckSum::add
* Inputs: * Inputs:
* unsigned int d: word to add * unsigned int d: word to add
* Result: void * Result: void
* *
* Effect: * Effect:
* Adds the bytes of the unsigned int to the CheckSum * Adds the bytes of the unsigned int to the CheckSum
****************************************************************************/ ****************************************************************************/
void CheckSum::Add ( unsigned int value ) void CheckSum::Add ( unsigned int value )
{ {
union union
{ {
unsigned int value; unsigned int value;
unsigned char bytes[ 4 ]; unsigned char bytes[ 4 ];
} }
data; data;
data.value = value; data.value = value;
for ( unsigned int i = 0; i < sizeof( data.bytes ); i++ ) for ( unsigned int i = 0; i < sizeof( data.bytes ); i++ )
Add ( data.bytes[ i ] ) Add ( data.bytes[ i ] )
; ;
} // CheckSum::add(unsigned int) } // CheckSum::add(unsigned int)
/**************************************************************************** /****************************************************************************
* CheckSum::add * CheckSum::add
* Inputs: * Inputs:
* unsigned short value: * unsigned short value:
* Result: void * Result: void
* *
* Effect: * Effect:
* Adds the bytes of the unsigned short value to the CheckSum * Adds the bytes of the unsigned short value to the CheckSum
****************************************************************************/ ****************************************************************************/
void CheckSum::Add ( unsigned short value ) void CheckSum::Add ( unsigned short value )
{ {
union union
{ {
unsigned short value; unsigned short value;
unsigned char bytes[ 2 ]; unsigned char bytes[ 2 ];
} }
data; data;
data.value = value; data.value = value;
for ( unsigned int i = 0; i < sizeof( data.bytes ); i++ ) for ( unsigned int i = 0; i < sizeof( data.bytes ); i++ )
Add ( data.bytes[ i ] ) Add ( data.bytes[ i ] )
; ;
} // CheckSum::add(unsigned short) } // CheckSum::add(unsigned short)
/**************************************************************************** /****************************************************************************
* CheckSum::add * CheckSum::add
* Inputs: * Inputs:
* unsigned char value: * unsigned char value:
* Result: void * Result: void
* *
* Effect: * Effect:
* Adds the byte to the CheckSum * Adds the byte to the CheckSum
****************************************************************************/ ****************************************************************************/
void CheckSum::Add ( unsigned char value ) void CheckSum::Add ( unsigned char value )
{ {
unsigned char cipher = (unsigned char)( value ^ ( r >> 8 ) ); unsigned char cipher = (unsigned char)( value ^ ( r >> 8 ) );
r = ( cipher + r ) * c1 + c2; r = ( cipher + r ) * c1 + c2;
sum += cipher; sum += cipher;
} // CheckSum::add(unsigned char) } // CheckSum::add(unsigned char)
/**************************************************************************** /****************************************************************************
* CheckSum::add * CheckSum::add
* Inputs: * Inputs:
* LPunsigned char b: pointer to byte array * LPunsigned char b: pointer to byte array
* unsigned int length: count * unsigned int length: count
* Result: void * Result: void
* *
* Effect: * Effect:
* Adds the bytes to the CheckSum * Adds the bytes to the CheckSum
****************************************************************************/ ****************************************************************************/
void CheckSum::Add ( unsigned char *b, unsigned int length ) void CheckSum::Add ( unsigned char *b, unsigned int length )
{ {
for ( unsigned int i = 0; i < length; i++ ) for ( unsigned int i = 0; i < length; i++ )
Add ( b[ i ] ) Add ( b[ i ] )
; ;
} // CheckSum::add(LPunsigned char, unsigned int) } // CheckSum::add(LPunsigned char, unsigned int)

View File

@@ -1,53 +1,53 @@
/// ///
/// \file CheckSum.cpp /// \file CheckSum.cpp
/// \brief [Internal] CheckSum implementation from http://www.flounder.com/checksum.htm /// \brief [Internal] CheckSum implementation from http://www.flounder.com/checksum.htm
/// ///
#ifndef __CHECKSUM_H #ifndef __CHECKSUM_H
#define __CHECKSUM_H #define __CHECKSUM_H
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
/// Generates and validates checksums /// Generates and validates checksums
class CheckSum class CheckSum
{ {
public: public:
/// Default constructor /// Default constructor
CheckSum() CheckSum()
{ {
Clear(); Clear();
} }
void Clear() void Clear()
{ {
sum = 0; sum = 0;
r = 55665; r = 55665;
c1 = 52845; c1 = 52845;
c2 = 22719; c2 = 22719;
} }
void Add ( unsigned int w ); void Add ( unsigned int w );
void Add ( unsigned short w ); void Add ( unsigned short w );
void Add ( unsigned char* b, unsigned int length ); void Add ( unsigned char* b, unsigned int length );
void Add ( unsigned char b ); void Add ( unsigned char b );
unsigned int Get () unsigned int Get ()
{ {
return sum; return sum;
} }
protected: protected:
unsigned short r; unsigned short r;
unsigned short c1; unsigned short c1;
unsigned short c2; unsigned short c2;
unsigned int sum; unsigned int sum;
}; };
#endif #endif

View File

@@ -1,242 +1,242 @@
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_CloudClient==1 #if _RAKNET_SUPPORT_CloudClient==1
#include "CloudClient.h" #include "CloudClient.h"
#include "GetTime.h" #include "GetTime.h"
#include "MessageIdentifiers.h" #include "MessageIdentifiers.h"
#include "BitStream.h" #include "BitStream.h"
#include "RakPeerInterface.h" #include "RakPeerInterface.h"
using namespace RakNet; using namespace RakNet;
STATIC_FACTORY_DEFINITIONS(CloudClient,CloudClient); STATIC_FACTORY_DEFINITIONS(CloudClient,CloudClient);
CloudClient::CloudClient() CloudClient::CloudClient()
{ {
callback=0; callback=0;
allocator=&unsetDefaultAllocator; allocator=&unsetDefaultAllocator;
} }
CloudClient::~CloudClient() CloudClient::~CloudClient()
{ {
} }
void CloudClient::SetDefaultCallbacks(CloudAllocator *_allocator, CloudClientCallback *_callback) void CloudClient::SetDefaultCallbacks(CloudAllocator *_allocator, CloudClientCallback *_callback)
{ {
callback=_callback; callback=_callback;
allocator=_allocator; allocator=_allocator;
} }
void CloudClient::Post(CloudKey *cloudKey, const unsigned char *data, uint32_t dataLengthBytes, RakNetGUID systemIdentifier) void CloudClient::Post(CloudKey *cloudKey, const unsigned char *data, uint32_t dataLengthBytes, RakNetGUID systemIdentifier)
{ {
RakAssert(cloudKey); RakAssert(cloudKey);
RakNet::BitStream bsOut; RakNet::BitStream bsOut;
bsOut.Write((MessageID)ID_CLOUD_POST_REQUEST); bsOut.Write((MessageID)ID_CLOUD_POST_REQUEST);
cloudKey->Serialize(true,&bsOut); cloudKey->Serialize(true,&bsOut);
if (data==0) if (data==0)
dataLengthBytes=0; dataLengthBytes=0;
bsOut.Write(dataLengthBytes); bsOut.Write(dataLengthBytes);
if (dataLengthBytes>0) if (dataLengthBytes>0)
bsOut.WriteAlignedBytes((const unsigned char*) data, dataLengthBytes); bsOut.WriteAlignedBytes((const unsigned char*) data, dataLengthBytes);
SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false);
} }
void CloudClient::Release(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier) void CloudClient::Release(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier)
{ {
RakNet::BitStream bsOut; RakNet::BitStream bsOut;
bsOut.Write((MessageID)ID_CLOUD_RELEASE_REQUEST); bsOut.Write((MessageID)ID_CLOUD_RELEASE_REQUEST);
RakAssert(keys.Size() < (uint16_t)-1 ); RakAssert(keys.Size() < (uint16_t)-1 );
bsOut.WriteCasted<uint16_t>(keys.Size()); bsOut.WriteCasted<uint16_t>(keys.Size());
for (uint16_t i=0; i < keys.Size(); i++) for (uint16_t i=0; i < keys.Size(); i++)
{ {
keys[i].Serialize(true,&bsOut); keys[i].Serialize(true,&bsOut);
} }
SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false);
} }
bool CloudClient::Get(CloudQuery *keyQuery, RakNetGUID systemIdentifier) bool CloudClient::Get(CloudQuery *keyQuery, RakNetGUID systemIdentifier)
{ {
RakNet::BitStream bsOut; RakNet::BitStream bsOut;
bsOut.Write((MessageID)ID_CLOUD_GET_REQUEST); bsOut.Write((MessageID)ID_CLOUD_GET_REQUEST);
keyQuery->Serialize(true, &bsOut); keyQuery->Serialize(true, &bsOut);
bsOut.WriteCasted<uint16_t>(0); // Specific systems bsOut.WriteCasted<uint16_t>(0); // Specific systems
SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false);
return true; return true;
} }
bool CloudClient::Get(CloudQuery *keyQuery, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier) bool CloudClient::Get(CloudQuery *keyQuery, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier)
{ {
RakNet::BitStream bsOut; RakNet::BitStream bsOut;
bsOut.Write((MessageID)ID_CLOUD_GET_REQUEST); bsOut.Write((MessageID)ID_CLOUD_GET_REQUEST);
keyQuery->Serialize(true, &bsOut); keyQuery->Serialize(true, &bsOut);
bsOut.WriteCasted<uint16_t>(specificSystems.Size()); bsOut.WriteCasted<uint16_t>(specificSystems.Size());
RakAssert(specificSystems.Size() < (uint16_t)-1 ); RakAssert(specificSystems.Size() < (uint16_t)-1 );
for (uint16_t i=0; i < specificSystems.Size(); i++) for (uint16_t i=0; i < specificSystems.Size(); i++)
{ {
bsOut.Write(specificSystems[i]); bsOut.Write(specificSystems[i]);
} }
SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false);
return true; return true;
} }
bool CloudClient::Get(CloudQuery *keyQuery, DataStructures::List<CloudQueryRow*> &specificSystems, RakNetGUID systemIdentifier) bool CloudClient::Get(CloudQuery *keyQuery, DataStructures::List<CloudQueryRow*> &specificSystems, RakNetGUID systemIdentifier)
{ {
RakNet::BitStream bsOut; RakNet::BitStream bsOut;
bsOut.Write((MessageID)ID_CLOUD_GET_REQUEST); bsOut.Write((MessageID)ID_CLOUD_GET_REQUEST);
keyQuery->Serialize(true, &bsOut); keyQuery->Serialize(true, &bsOut);
bsOut.WriteCasted<uint16_t>(specificSystems.Size()); bsOut.WriteCasted<uint16_t>(specificSystems.Size());
RakAssert(specificSystems.Size() < (uint16_t)-1 ); RakAssert(specificSystems.Size() < (uint16_t)-1 );
for (uint16_t i=0; i < specificSystems.Size(); i++) for (uint16_t i=0; i < specificSystems.Size(); i++)
{ {
if (specificSystems[i]->clientGUID!=UNASSIGNED_RAKNET_GUID) if (specificSystems[i]->clientGUID!=UNASSIGNED_RAKNET_GUID)
{ {
bsOut.Write(true); bsOut.Write(true);
bsOut.Write(specificSystems[i]->clientGUID); bsOut.Write(specificSystems[i]->clientGUID);
} }
else else
{ {
bsOut.Write(false); bsOut.Write(false);
bsOut.Write(specificSystems[i]->clientSystemAddress); bsOut.Write(specificSystems[i]->clientSystemAddress);
} }
} }
SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false);
return true; return true;
} }
void CloudClient::Unsubscribe(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier) void CloudClient::Unsubscribe(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier)
{ {
RakNet::BitStream bsOut; RakNet::BitStream bsOut;
bsOut.Write((MessageID)ID_CLOUD_UNSUBSCRIBE_REQUEST); bsOut.Write((MessageID)ID_CLOUD_UNSUBSCRIBE_REQUEST);
RakAssert(keys.Size() < (uint16_t)-1 ); RakAssert(keys.Size() < (uint16_t)-1 );
bsOut.WriteCasted<uint16_t>(keys.Size()); bsOut.WriteCasted<uint16_t>(keys.Size());
for (uint16_t i=0; i < keys.Size(); i++) for (uint16_t i=0; i < keys.Size(); i++)
{ {
keys[i].Serialize(true,&bsOut); keys[i].Serialize(true,&bsOut);
} }
bsOut.WriteCasted<uint16_t>(0); bsOut.WriteCasted<uint16_t>(0);
SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false);
} }
void CloudClient::Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier) void CloudClient::Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier)
{ {
RakNet::BitStream bsOut; RakNet::BitStream bsOut;
bsOut.Write((MessageID)ID_CLOUD_UNSUBSCRIBE_REQUEST); bsOut.Write((MessageID)ID_CLOUD_UNSUBSCRIBE_REQUEST);
RakAssert(keys.Size() < (uint16_t)-1 ); RakAssert(keys.Size() < (uint16_t)-1 );
bsOut.WriteCasted<uint16_t>(keys.Size()); bsOut.WriteCasted<uint16_t>(keys.Size());
for (uint16_t i=0; i < keys.Size(); i++) for (uint16_t i=0; i < keys.Size(); i++)
{ {
keys[i].Serialize(true,&bsOut); keys[i].Serialize(true,&bsOut);
} }
bsOut.WriteCasted<uint16_t>(specificSystems.Size()); bsOut.WriteCasted<uint16_t>(specificSystems.Size());
RakAssert(specificSystems.Size() < (uint16_t)-1 ); RakAssert(specificSystems.Size() < (uint16_t)-1 );
for (uint16_t i=0; i < specificSystems.Size(); i++) for (uint16_t i=0; i < specificSystems.Size(); i++)
{ {
bsOut.Write(specificSystems[i]); bsOut.Write(specificSystems[i]);
} }
SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false);
} }
void CloudClient::Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<CloudQueryRow*> &specificSystems, RakNetGUID systemIdentifier) void CloudClient::Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<CloudQueryRow*> &specificSystems, RakNetGUID systemIdentifier)
{ {
RakNet::BitStream bsOut; RakNet::BitStream bsOut;
bsOut.Write((MessageID)ID_CLOUD_UNSUBSCRIBE_REQUEST); bsOut.Write((MessageID)ID_CLOUD_UNSUBSCRIBE_REQUEST);
RakAssert(keys.Size() < (uint16_t)-1 ); RakAssert(keys.Size() < (uint16_t)-1 );
bsOut.WriteCasted<uint16_t>(keys.Size()); bsOut.WriteCasted<uint16_t>(keys.Size());
for (uint16_t i=0; i < keys.Size(); i++) for (uint16_t i=0; i < keys.Size(); i++)
{ {
keys[i].Serialize(true,&bsOut); keys[i].Serialize(true,&bsOut);
} }
bsOut.WriteCasted<uint16_t>(specificSystems.Size()); bsOut.WriteCasted<uint16_t>(specificSystems.Size());
RakAssert(specificSystems.Size() < (uint16_t)-1 ); RakAssert(specificSystems.Size() < (uint16_t)-1 );
for (uint16_t i=0; i < specificSystems.Size(); i++) for (uint16_t i=0; i < specificSystems.Size(); i++)
{ {
if (specificSystems[i]->clientGUID!=UNASSIGNED_RAKNET_GUID) if (specificSystems[i]->clientGUID!=UNASSIGNED_RAKNET_GUID)
{ {
bsOut.Write(true); bsOut.Write(true);
bsOut.Write(specificSystems[i]->clientGUID); bsOut.Write(specificSystems[i]->clientGUID);
} }
else else
{ {
bsOut.Write(false); bsOut.Write(false);
bsOut.Write(specificSystems[i]->clientSystemAddress); bsOut.Write(specificSystems[i]->clientSystemAddress);
} }
} }
SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false);
} }
PluginReceiveResult CloudClient::OnReceive(Packet *packet) PluginReceiveResult CloudClient::OnReceive(Packet *packet)
{ {
(void) packet; (void) packet;
return RR_CONTINUE_PROCESSING; return RR_CONTINUE_PROCESSING;
} }
void CloudClient::OnGetReponse(Packet *packet, CloudClientCallback *_callback, CloudAllocator *_allocator) void CloudClient::OnGetReponse(Packet *packet, CloudClientCallback *_callback, CloudAllocator *_allocator)
{ {
if (_callback==0) if (_callback==0)
_callback=callback; _callback=callback;
if (_allocator==0) if (_allocator==0)
_allocator=allocator; _allocator=allocator;
CloudQueryResult cloudQueryResult; CloudQueryResult cloudQueryResult;
RakNet::BitStream bsIn(packet->data, packet->length, false); RakNet::BitStream bsIn(packet->data, packet->length, false);
bsIn.IgnoreBytes(sizeof(MessageID)); bsIn.IgnoreBytes(sizeof(MessageID));
cloudQueryResult.Serialize(false,&bsIn,_allocator); cloudQueryResult.Serialize(false,&bsIn,_allocator);
bool deallocateRowsAfterReturn=true; bool deallocateRowsAfterReturn=true;
_callback->OnGet(&cloudQueryResult, &deallocateRowsAfterReturn); _callback->OnGet(&cloudQueryResult, &deallocateRowsAfterReturn);
if (deallocateRowsAfterReturn) if (deallocateRowsAfterReturn)
{ {
unsigned int i; unsigned int i;
for (i=0; i < cloudQueryResult.rowsReturned.Size(); i++) for (i=0; i < cloudQueryResult.rowsReturned.Size(); i++)
{ {
_allocator->DeallocateRowData(cloudQueryResult.rowsReturned[i]->data); _allocator->DeallocateRowData(cloudQueryResult.rowsReturned[i]->data);
_allocator->DeallocateCloudQueryRow(cloudQueryResult.rowsReturned[i]); _allocator->DeallocateCloudQueryRow(cloudQueryResult.rowsReturned[i]);
} }
} }
} }
void CloudClient::OnGetReponse(CloudQueryResult *cloudQueryResult, Packet *packet, CloudAllocator *_allocator) void CloudClient::OnGetReponse(CloudQueryResult *cloudQueryResult, Packet *packet, CloudAllocator *_allocator)
{ {
if (_allocator==0) if (_allocator==0)
_allocator=allocator; _allocator=allocator;
RakNet::BitStream bsIn(packet->data, packet->length, false); RakNet::BitStream bsIn(packet->data, packet->length, false);
bsIn.IgnoreBytes(sizeof(MessageID)); bsIn.IgnoreBytes(sizeof(MessageID));
cloudQueryResult->Serialize(false,&bsIn,_allocator); cloudQueryResult->Serialize(false,&bsIn,_allocator);
} }
void CloudClient::OnSubscriptionNotification(Packet *packet, CloudClientCallback *_callback, CloudAllocator *_allocator) void CloudClient::OnSubscriptionNotification(Packet *packet, CloudClientCallback *_callback, CloudAllocator *_allocator)
{ {
if (_callback==0) if (_callback==0)
_callback=callback; _callback=callback;
if (_allocator==0) if (_allocator==0)
_allocator=allocator; _allocator=allocator;
bool wasUpdated=false; bool wasUpdated=false;
CloudQueryRow row; CloudQueryRow row;
RakNet::BitStream bsIn(packet->data, packet->length, false); RakNet::BitStream bsIn(packet->data, packet->length, false);
bsIn.IgnoreBytes(sizeof(MessageID)); bsIn.IgnoreBytes(sizeof(MessageID));
bsIn.Read(wasUpdated); bsIn.Read(wasUpdated);
row.Serialize(false,&bsIn,_allocator); row.Serialize(false,&bsIn,_allocator);
bool deallocateRowAfterReturn=true; bool deallocateRowAfterReturn=true;
_callback->OnSubscriptionNotification(&row, wasUpdated, &deallocateRowAfterReturn); _callback->OnSubscriptionNotification(&row, wasUpdated, &deallocateRowAfterReturn);
if (deallocateRowAfterReturn) if (deallocateRowAfterReturn)
{ {
_allocator->DeallocateRowData(row.data); _allocator->DeallocateRowData(row.data);
} }
} }
void CloudClient::OnSubscriptionNotification(bool *wasUpdated, CloudQueryRow *row, Packet *packet, CloudAllocator *_allocator) void CloudClient::OnSubscriptionNotification(bool *wasUpdated, CloudQueryRow *row, Packet *packet, CloudAllocator *_allocator)
{ {
if (_allocator==0) if (_allocator==0)
_allocator=allocator; _allocator=allocator;
RakNet::BitStream bsIn(packet->data, packet->length, false); RakNet::BitStream bsIn(packet->data, packet->length, false);
bsIn.IgnoreBytes(sizeof(MessageID)); bsIn.IgnoreBytes(sizeof(MessageID));
bool b=false; bool b=false;
bsIn.Read(b); bsIn.Read(b);
*wasUpdated=b; *wasUpdated=b;
row->Serialize(false,&bsIn,_allocator); row->Serialize(false,&bsIn,_allocator);
} }
void CloudClient::DeallocateWithDefaultAllocator(CloudQueryResult *cloudQueryResult) void CloudClient::DeallocateWithDefaultAllocator(CloudQueryResult *cloudQueryResult)
{ {
unsigned int i; unsigned int i;
for (i=0; i < cloudQueryResult->rowsReturned.Size(); i++) for (i=0; i < cloudQueryResult->rowsReturned.Size(); i++)
{ {
allocator->DeallocateRowData(cloudQueryResult->rowsReturned[i]->data); allocator->DeallocateRowData(cloudQueryResult->rowsReturned[i]->data);
allocator->DeallocateCloudQueryRow(cloudQueryResult->rowsReturned[i]); allocator->DeallocateCloudQueryRow(cloudQueryResult->rowsReturned[i]);
} }
} }
void CloudClient::DeallocateWithDefaultAllocator(CloudQueryRow *row) void CloudClient::DeallocateWithDefaultAllocator(CloudQueryRow *row)
{ {
allocator->DeallocateRowData(row->data); allocator->DeallocateRowData(row->data);
} }
#endif #endif

View File

@@ -1,163 +1,163 @@
/// \file CloudClient.h /// \file CloudClient.h
/// \brief Queries CloudMemoryServer to download data that other clients have uploaded /// \brief Queries CloudMemoryServer to download data that other clients have uploaded
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_CloudClient==1 #if _RAKNET_SUPPORT_CloudClient==1
#ifndef __CLOUD_CLIENT_H #ifndef __CLOUD_CLIENT_H
#define __CLOUD_CLIENT_H #define __CLOUD_CLIENT_H
#include "PluginInterface2.h" #include "PluginInterface2.h"
#include "CloudCommon.h" #include "CloudCommon.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "DS_Hash.h" #include "DS_Hash.h"
namespace RakNet namespace RakNet
{ {
/// Forward declarations /// Forward declarations
class RakPeerInterface; class RakPeerInterface;
class CloudClientCallback; class CloudClientCallback;
/// \defgroup CLOUD_GROUP CloudComputing /// \defgroup CLOUD_GROUP CloudComputing
/// \brief Contains the CloudClient and CloudServer plugins /// \brief Contains the CloudClient and CloudServer plugins
/// \details The CloudServer plugins operates on requests from the CloudClient plugin. The servers are in a fully connected mesh topology, which the clients are connected to any server. Clients can interact with each other by posting and subscribing to memory updates, without being directly connected or even knowing about each other. /// \details The CloudServer plugins operates on requests from the CloudClient plugin. The servers are in a fully connected mesh topology, which the clients are connected to any server. Clients can interact with each other by posting and subscribing to memory updates, without being directly connected or even knowing about each other.
/// \ingroup PLUGINS_GROUP /// \ingroup PLUGINS_GROUP
/// \brief Performs Post() and Get() operations on CloudMemoryServer /// \brief Performs Post() and Get() operations on CloudMemoryServer
/// \details A CloudClient is a computer connected to one or more servers in a cloud configuration. Operations by one CloudClient can be received and subscribed to by other instances of CloudClient, without those clients being connected, even on different servers. /// \details A CloudClient is a computer connected to one or more servers in a cloud configuration. Operations by one CloudClient can be received and subscribed to by other instances of CloudClient, without those clients being connected, even on different servers.
/// \ingroup CLOUD_GROUP /// \ingroup CLOUD_GROUP
class RAK_DLL_EXPORT CloudClient : public PluginInterface2 class RAK_DLL_EXPORT CloudClient : public PluginInterface2
{ {
public: public:
// GetInstance() and DestroyInstance(instance*) // GetInstance() and DestroyInstance(instance*)
STATIC_FACTORY_DECLARATIONS(CloudClient) STATIC_FACTORY_DECLARATIONS(CloudClient)
CloudClient(); CloudClient();
virtual ~CloudClient(); virtual ~CloudClient();
/// \brief Set the default callbacks for OnGetReponse(), OnSubscriptionNotification(), and OnSubscriptionDataDeleted() /// \brief Set the default callbacks for OnGetReponse(), OnSubscriptionNotification(), and OnSubscriptionDataDeleted()
/// \details Pointers to CloudAllocator and CloudClientCallback can be stored by the system if desired. If a callback is not provided to OnGetReponse(), OnSubscriptionNotification(), OnSubscriptionDataDeleted(), the callback passed here will be used instead. /// \details Pointers to CloudAllocator and CloudClientCallback can be stored by the system if desired. If a callback is not provided to OnGetReponse(), OnSubscriptionNotification(), OnSubscriptionDataDeleted(), the callback passed here will be used instead.
/// \param[in] _allocator An instance of CloudAllocator /// \param[in] _allocator An instance of CloudAllocator
/// \param[in] _callback An instance of CloudClientCallback /// \param[in] _callback An instance of CloudClientCallback
virtual void SetDefaultCallbacks(CloudAllocator *_allocator, CloudClientCallback *_callback); virtual void SetDefaultCallbacks(CloudAllocator *_allocator, CloudClientCallback *_callback);
/// \brief Uploads data to the cloud /// \brief Uploads data to the cloud
/// \details Data uploaded to the cloud will be stored by the server sent to, identified by \a systemIdentifier. /// \details Data uploaded to the cloud will be stored by the server sent to, identified by \a systemIdentifier.
/// As long as you are connected to this server, the data will persist. Queries for that data by the Get() operation will /// As long as you are connected to this server, the data will persist. Queries for that data by the Get() operation will
/// return the RakNetGUID and SystemAddress of the uploader, as well as the data itself. /// return the RakNetGUID and SystemAddress of the uploader, as well as the data itself.
/// Furthermore, if any clients are subscribed to the particular CloudKey passed, those clients will get update notices that the data has changed /// Furthermore, if any clients are subscribed to the particular CloudKey passed, those clients will get update notices that the data has changed
/// Passing data with the same \a cloudKey more than once will overwrite the prior value. /// Passing data with the same \a cloudKey more than once will overwrite the prior value.
/// This call will silently fail if CloudServer::SetMaxUploadBytesPerClient() is exceeded /// This call will silently fail if CloudServer::SetMaxUploadBytesPerClient() is exceeded
/// \param[in] cloudKey Identifies the data being uploaded /// \param[in] cloudKey Identifies the data being uploaded
/// \param[in] data A pointer to data to upload. This pointer does not need to persist past the call /// \param[in] data A pointer to data to upload. This pointer does not need to persist past the call
/// \param[in] dataLengthBytes The length in bytes of \a data /// \param[in] dataLengthBytes The length in bytes of \a data
/// \param[in] systemIdentifier A remote system running CloudServer that we are already connected to. /// \param[in] systemIdentifier A remote system running CloudServer that we are already connected to.
virtual void Post(CloudKey *cloudKey, const unsigned char *data, uint32_t dataLengthBytes, RakNetGUID systemIdentifier); virtual void Post(CloudKey *cloudKey, const unsigned char *data, uint32_t dataLengthBytes, RakNetGUID systemIdentifier);
/// \brief Releases one or more data previously uploaded with Post() /// \brief Releases one or more data previously uploaded with Post()
/// \details If a remote system has subscribed to one or more of the \a keys uploaded, they will get ID_CLOUD_SUBSCRIPTION_NOTIFICATION notifications containing the last value uploaded before deletions /// \details If a remote system has subscribed to one or more of the \a keys uploaded, they will get ID_CLOUD_SUBSCRIPTION_NOTIFICATION notifications containing the last value uploaded before deletions
/// \param[in] cloudKey Identifies the data to release. It is possible to remove uploads from multiple Post() calls at once. /// \param[in] cloudKey Identifies the data to release. It is possible to remove uploads from multiple Post() calls at once.
/// \param[in] systemIdentifier A remote system running CloudServer that we are already connected to. /// \param[in] systemIdentifier A remote system running CloudServer that we are already connected to.
virtual void Release(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier); virtual void Release(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier);
/// \brief Gets data from the cloud /// \brief Gets data from the cloud
/// \details For a given query containing one or more keys, return data that matches those keys. /// \details For a given query containing one or more keys, return data that matches those keys.
/// The values will be returned in the ID_CLOUD_GET_RESPONSE packet, which should be passed to OnGetReponse() and will invoke CloudClientCallback::OnGet() /// The values will be returned in the ID_CLOUD_GET_RESPONSE packet, which should be passed to OnGetReponse() and will invoke CloudClientCallback::OnGet()
/// CloudQuery::startingRowIndex is used to skip the first n values that would normally be returned.. /// CloudQuery::startingRowIndex is used to skip the first n values that would normally be returned..
/// CloudQuery::maxRowsToReturn is used to limit the number of rows returned. The number of rows returned may also be limited by CloudServer::SetMaxBytesPerDownload(); /// CloudQuery::maxRowsToReturn is used to limit the number of rows returned. The number of rows returned may also be limited by CloudServer::SetMaxBytesPerDownload();
/// CloudQuery::subscribeToResults if set to true, will cause ID_CLOUD_SUBSCRIPTION_NOTIFICATION to be returned to us when any of the keys in the query are updated or are deleted. /// CloudQuery::subscribeToResults if set to true, will cause ID_CLOUD_SUBSCRIPTION_NOTIFICATION to be returned to us when any of the keys in the query are updated or are deleted.
/// ID_CLOUD_GET_RESPONSE will be returned even if subscribing to the result list. Only later updates will return ID_CLOUD_SUBSCRIPTION_NOTIFICATION. /// ID_CLOUD_GET_RESPONSE will be returned even if subscribing to the result list. Only later updates will return ID_CLOUD_SUBSCRIPTION_NOTIFICATION.
/// Calling Get() with CloudQuery::subscribeToResults false, when you are already subscribed, does not remove the subscription. Use Unsubscribe() for this. /// Calling Get() with CloudQuery::subscribeToResults false, when you are already subscribed, does not remove the subscription. Use Unsubscribe() for this.
/// Resubscribing using the same CloudKey but a different or no \a specificSystems overwrites the subscribed systems for those keys. /// Resubscribing using the same CloudKey but a different or no \a specificSystems overwrites the subscribed systems for those keys.
/// \param[in] cloudQuery One or more keys, and optional parameters to perform with the Get /// \param[in] cloudQuery One or more keys, and optional parameters to perform with the Get
/// \param[in] systemIdentifier A remote system running CloudServer that we are already connected to. /// \param[in] systemIdentifier A remote system running CloudServer that we are already connected to.
/// \param[in] specificSystems It is possible to get or subscribe to updates only for specific uploading CloudClient instances. Pass the desired instances here. The overload that does not have the specificSystems parameter is treated as subscribing to all updates from all clients. /// \param[in] specificSystems It is possible to get or subscribe to updates only for specific uploading CloudClient instances. Pass the desired instances here. The overload that does not have the specificSystems parameter is treated as subscribing to all updates from all clients.
virtual bool Get(CloudQuery *cloudQuery, RakNetGUID systemIdentifier); virtual bool Get(CloudQuery *cloudQuery, RakNetGUID systemIdentifier);
virtual bool Get(CloudQuery *cloudQuery, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier); virtual bool Get(CloudQuery *cloudQuery, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier);
virtual bool Get(CloudQuery *cloudQuery, DataStructures::List<CloudQueryRow*> &specificSystems, RakNetGUID systemIdentifier); virtual bool Get(CloudQuery *cloudQuery, DataStructures::List<CloudQueryRow*> &specificSystems, RakNetGUID systemIdentifier);
/// \brief Unsubscribe from updates previously subscribed to using Get() with the CloudQuery::subscribeToResults set to true /// \brief Unsubscribe from updates previously subscribed to using Get() with the CloudQuery::subscribeToResults set to true
/// The \a keys and \a specificSystems parameters are logically treated as AND when checking subscriptions on the server /// The \a keys and \a specificSystems parameters are logically treated as AND when checking subscriptions on the server
/// The overload that does not take specificSystems unsubscribes to all passed keys, regardless of system /// The overload that does not take specificSystems unsubscribes to all passed keys, regardless of system
/// You cannot unsubscribe specific systems when previously subscribed to updates from any system. To do this, first Unsubscribe() from all systems, and call Get() with the \a specificSystems parameter explicilty listing the systems you want to subscribe to. /// You cannot unsubscribe specific systems when previously subscribed to updates from any system. To do this, first Unsubscribe() from all systems, and call Get() with the \a specificSystems parameter explicilty listing the systems you want to subscribe to.
virtual void Unsubscribe(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier); virtual void Unsubscribe(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier);
virtual void Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier); virtual void Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier);
virtual void Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<CloudQueryRow*> &specificSystems, RakNetGUID systemIdentifier); virtual void Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<CloudQueryRow*> &specificSystems, RakNetGUID systemIdentifier);
/// \brief Call this when you get ID_CLOUD_GET_RESPONSE /// \brief Call this when you get ID_CLOUD_GET_RESPONSE
/// If \a callback or \a allocator are 0, the default callbacks passed to SetDefaultCallbacks() are used /// If \a callback or \a allocator are 0, the default callbacks passed to SetDefaultCallbacks() are used
/// \param[in] packet Packet structure returned from RakPeerInterface /// \param[in] packet Packet structure returned from RakPeerInterface
/// \param[in] _callback Callback to be called from the function containing output parameters. If 0, default is used. /// \param[in] _callback Callback to be called from the function containing output parameters. If 0, default is used.
/// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used. /// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used.
virtual void OnGetReponse(Packet *packet, CloudClientCallback *_callback=0, CloudAllocator *_allocator=0); virtual void OnGetReponse(Packet *packet, CloudClientCallback *_callback=0, CloudAllocator *_allocator=0);
/// \brief Call this when you get ID_CLOUD_GET_RESPONSE /// \brief Call this when you get ID_CLOUD_GET_RESPONSE
/// Different form of OnGetReponse that returns to a structure that you pass, instead of using a callback /// Different form of OnGetReponse that returns to a structure that you pass, instead of using a callback
/// You are responsible for deallocation with this form /// You are responsible for deallocation with this form
/// If \a allocator is 0, the default callback passed to SetDefaultCallbacks() are used /// If \a allocator is 0, the default callback passed to SetDefaultCallbacks() are used
/// \param[out] cloudQueryResult A pointer to a structure that will be filled out with data /// \param[out] cloudQueryResult A pointer to a structure that will be filled out with data
/// \param[in] packet Packet structure returned from RakPeerInterface /// \param[in] packet Packet structure returned from RakPeerInterface
/// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used. /// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used.
virtual void OnGetReponse(CloudQueryResult *cloudQueryResult, Packet *packet, CloudAllocator *_allocator=0); virtual void OnGetReponse(CloudQueryResult *cloudQueryResult, Packet *packet, CloudAllocator *_allocator=0);
/// \brief Call this when you get ID_CLOUD_SUBSCRIPTION_NOTIFICATION /// \brief Call this when you get ID_CLOUD_SUBSCRIPTION_NOTIFICATION
/// If \a callback or \a allocator are 0, the default callbacks passed to SetDefaultCallbacks() are used /// If \a callback or \a allocator are 0, the default callbacks passed to SetDefaultCallbacks() are used
/// \param[in] packet Packet structure returned from RakPeerInterface /// \param[in] packet Packet structure returned from RakPeerInterface
/// \param[in] _callback Callback to be called from the function containing output parameters. If 0, default is used. /// \param[in] _callback Callback to be called from the function containing output parameters. If 0, default is used.
/// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used. /// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used.
virtual void OnSubscriptionNotification(Packet *packet, CloudClientCallback *_callback=0, CloudAllocator *_allocator=0); virtual void OnSubscriptionNotification(Packet *packet, CloudClientCallback *_callback=0, CloudAllocator *_allocator=0);
/// \brief Call this when you get ID_CLOUD_SUBSCRIPTION_NOTIFICATION /// \brief Call this when you get ID_CLOUD_SUBSCRIPTION_NOTIFICATION
/// Different form of OnSubscriptionNotification that returns to a structure that you pass, instead of using a callback /// Different form of OnSubscriptionNotification that returns to a structure that you pass, instead of using a callback
/// You are responsible for deallocation with this form /// You are responsible for deallocation with this form
/// If \a allocator is 0, the default callback passed to SetDefaultCallbacks() are used /// If \a allocator is 0, the default callback passed to SetDefaultCallbacks() are used
/// \param[out] wasUpdated If true, the row was updated. If false, it was deleted. \a result will contain the last value just before deletion /// \param[out] wasUpdated If true, the row was updated. If false, it was deleted. \a result will contain the last value just before deletion
/// \param[out] row A pointer to a structure that will be filled out with data /// \param[out] row A pointer to a structure that will be filled out with data
/// \param[in] packet Packet structure returned from RakPeerInterface /// \param[in] packet Packet structure returned from RakPeerInterface
/// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used. /// \param[in] _allocator Allocator to be used to allocate data. If 0, default is used.
virtual void OnSubscriptionNotification(bool *wasUpdated, CloudQueryRow *row, Packet *packet, CloudAllocator *_allocator=0); virtual void OnSubscriptionNotification(bool *wasUpdated, CloudQueryRow *row, Packet *packet, CloudAllocator *_allocator=0);
/// If you never specified an allocator, and used the non-callback form of OnGetReponse(), deallocate cloudQueryResult with this function /// If you never specified an allocator, and used the non-callback form of OnGetReponse(), deallocate cloudQueryResult with this function
virtual void DeallocateWithDefaultAllocator(CloudQueryResult *cloudQueryResult); virtual void DeallocateWithDefaultAllocator(CloudQueryResult *cloudQueryResult);
/// If you never specified an allocator, and used the non-callback form of OnSubscriptionNotification(), deallocate row with this function /// If you never specified an allocator, and used the non-callback form of OnSubscriptionNotification(), deallocate row with this function
virtual void DeallocateWithDefaultAllocator(CloudQueryRow *row); virtual void DeallocateWithDefaultAllocator(CloudQueryRow *row);
protected: protected:
PluginReceiveResult OnReceive(Packet *packet); PluginReceiveResult OnReceive(Packet *packet);
CloudClientCallback *callback; CloudClientCallback *callback;
CloudAllocator *allocator; CloudAllocator *allocator;
CloudAllocator unsetDefaultAllocator; CloudAllocator unsetDefaultAllocator;
}; };
/// \ingroup CLOUD_GROUP /// \ingroup CLOUD_GROUP
/// Parses ID_CLOUD_GET_RESPONSE and ID_CLOUD_SUBSCRIPTION_NOTIFICATION in a convenient callback form /// Parses ID_CLOUD_GET_RESPONSE and ID_CLOUD_SUBSCRIPTION_NOTIFICATION in a convenient callback form
class RAK_DLL_EXPORT CloudClientCallback class RAK_DLL_EXPORT CloudClientCallback
{ {
public: public:
CloudClientCallback() {} CloudClientCallback() {}
virtual ~CloudClientCallback() {} virtual ~CloudClientCallback() {}
/// \brief Called in response to ID_CLOUD_GET_RESPONSE /// \brief Called in response to ID_CLOUD_GET_RESPONSE
/// \param[out] result Contains the original query passed to Get(), and a list of rows returned. /// \param[out] result Contains the original query passed to Get(), and a list of rows returned.
/// \param[out] deallocateRowsAfterReturn CloudQueryResult::rowsReturned will be deallocated after the function returns by default. Set to false to not deallocate these pointers. The pointers are allocated through CloudAllocator. /// \param[out] deallocateRowsAfterReturn CloudQueryResult::rowsReturned will be deallocated after the function returns by default. Set to false to not deallocate these pointers. The pointers are allocated through CloudAllocator.
virtual void OnGet(RakNet::CloudQueryResult *result, bool *deallocateRowsAfterReturn) {(void) result; (void) deallocateRowsAfterReturn;} virtual void OnGet(RakNet::CloudQueryResult *result, bool *deallocateRowsAfterReturn) {(void) result; (void) deallocateRowsAfterReturn;}
/// \brief Called in response to ID_CLOUD_SUBSCRIPTION_NOTIFICATION /// \brief Called in response to ID_CLOUD_SUBSCRIPTION_NOTIFICATION
/// \param[out] result Contains the row updated /// \param[out] result Contains the row updated
/// \param[out] wasUpdated If true, the row was updated. If false, it was deleted. \a result will contain the last value just before deletion /// \param[out] wasUpdated If true, the row was updated. If false, it was deleted. \a result will contain the last value just before deletion
/// \param[out] deallocateRowAfterReturn \a result will be deallocated after the function returns by default. Set to false to not deallocate these pointers. The pointers are allocated through CloudAllocator. /// \param[out] deallocateRowAfterReturn \a result will be deallocated after the function returns by default. Set to false to not deallocate these pointers. The pointers are allocated through CloudAllocator.
virtual void OnSubscriptionNotification(RakNet::CloudQueryRow *result, bool wasUpdated, bool *deallocateRowAfterReturn) {(void) result; (void) wasUpdated; (void) deallocateRowAfterReturn;} virtual void OnSubscriptionNotification(RakNet::CloudQueryRow *result, bool wasUpdated, bool *deallocateRowAfterReturn) {(void) result; (void) wasUpdated; (void) deallocateRowAfterReturn;}
}; };
} // namespace RakNet } // namespace RakNet
#endif #endif
#endif // _RAKNET_SUPPORT_* #endif // _RAKNET_SUPPORT_*

View File

@@ -1,159 +1,159 @@
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_CloudClient==1 || _RAKNET_SUPPORT_CloudServer==1 #if _RAKNET_SUPPORT_CloudClient==1 || _RAKNET_SUPPORT_CloudServer==1
#include "CloudCommon.h" #include "CloudCommon.h"
#include "BitStream.h" #include "BitStream.h"
using namespace RakNet; using namespace RakNet;
int RakNet::CloudKeyComp(const CloudKey &key, const CloudKey &data) int RakNet::CloudKeyComp(const CloudKey &key, const CloudKey &data)
{ {
if (key.primaryKey < data.primaryKey) if (key.primaryKey < data.primaryKey)
return -1; return -1;
if (key.primaryKey > data.primaryKey) if (key.primaryKey > data.primaryKey)
return 1; return 1;
if (key.secondaryKey < data.secondaryKey) if (key.secondaryKey < data.secondaryKey)
return -1; return -1;
if (key.secondaryKey > data.secondaryKey) if (key.secondaryKey > data.secondaryKey)
return 1; return 1;
return 0; return 0;
} }
CloudQueryRow* CloudAllocator::AllocateCloudQueryRow(void) CloudQueryRow* CloudAllocator::AllocateCloudQueryRow(void)
{ {
return RakNet::OP_NEW<CloudQueryRow>(_FILE_AND_LINE_); return RakNet::OP_NEW<CloudQueryRow>(_FILE_AND_LINE_);
} }
void CloudAllocator::DeallocateCloudQueryRow(CloudQueryRow *row) void CloudAllocator::DeallocateCloudQueryRow(CloudQueryRow *row)
{ {
RakNet::OP_DELETE(row,_FILE_AND_LINE_); RakNet::OP_DELETE(row,_FILE_AND_LINE_);
} }
unsigned char *CloudAllocator::AllocateRowData(uint32_t bytesNeededForData) unsigned char *CloudAllocator::AllocateRowData(uint32_t bytesNeededForData)
{ {
return (unsigned char*) rakMalloc_Ex(bytesNeededForData,_FILE_AND_LINE_); return (unsigned char*) rakMalloc_Ex(bytesNeededForData,_FILE_AND_LINE_);
} }
void CloudAllocator::DeallocateRowData(void *data) void CloudAllocator::DeallocateRowData(void *data)
{ {
rakFree_Ex(data, _FILE_AND_LINE_); rakFree_Ex(data, _FILE_AND_LINE_);
} }
void CloudKey::Serialize(bool writeToBitstream, BitStream *bitStream) void CloudKey::Serialize(bool writeToBitstream, BitStream *bitStream)
{ {
bitStream->Serialize(writeToBitstream, primaryKey); bitStream->Serialize(writeToBitstream, primaryKey);
bitStream->Serialize(writeToBitstream, secondaryKey); bitStream->Serialize(writeToBitstream, secondaryKey);
} }
void CloudQuery::Serialize(bool writeToBitstream, BitStream *bitStream) void CloudQuery::Serialize(bool writeToBitstream, BitStream *bitStream)
{ {
bool startingRowIndexIsZero=0; bool startingRowIndexIsZero=0;
bool maxRowsToReturnIsZero=0; bool maxRowsToReturnIsZero=0;
startingRowIndexIsZero=startingRowIndex==0; startingRowIndexIsZero=startingRowIndex==0;
maxRowsToReturnIsZero=maxRowsToReturn==0; maxRowsToReturnIsZero=maxRowsToReturn==0;
bitStream->Serialize(writeToBitstream,startingRowIndexIsZero); bitStream->Serialize(writeToBitstream,startingRowIndexIsZero);
bitStream->Serialize(writeToBitstream,maxRowsToReturnIsZero); bitStream->Serialize(writeToBitstream,maxRowsToReturnIsZero);
bitStream->Serialize(writeToBitstream,subscribeToResults); bitStream->Serialize(writeToBitstream,subscribeToResults);
if (startingRowIndexIsZero==false) if (startingRowIndexIsZero==false)
bitStream->Serialize(writeToBitstream,startingRowIndex); bitStream->Serialize(writeToBitstream,startingRowIndex);
if (maxRowsToReturnIsZero==false) if (maxRowsToReturnIsZero==false)
bitStream->Serialize(writeToBitstream,maxRowsToReturn); bitStream->Serialize(writeToBitstream,maxRowsToReturn);
RakAssert(keys.Size()<(uint16_t)-1); RakAssert(keys.Size()<(uint16_t)-1);
uint16_t numKeys = (uint16_t) keys.Size(); uint16_t numKeys = (uint16_t) keys.Size();
bitStream->Serialize(writeToBitstream,numKeys); bitStream->Serialize(writeToBitstream,numKeys);
if (writeToBitstream) if (writeToBitstream)
{ {
for (uint16_t i=0; i < numKeys; i++) for (uint16_t i=0; i < numKeys; i++)
{ {
keys[i].Serialize(true,bitStream); keys[i].Serialize(true,bitStream);
} }
} }
else else
{ {
CloudKey cmdk; CloudKey cmdk;
for (uint16_t i=0; i < numKeys; i++) for (uint16_t i=0; i < numKeys; i++)
{ {
cmdk.Serialize(false,bitStream); cmdk.Serialize(false,bitStream);
keys.Push(cmdk, _FILE_AND_LINE_); keys.Push(cmdk, _FILE_AND_LINE_);
} }
} }
} }
void CloudQueryRow::Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator) void CloudQueryRow::Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator)
{ {
key.Serialize(writeToBitstream,bitStream); key.Serialize(writeToBitstream,bitStream);
bitStream->Serialize(writeToBitstream,serverSystemAddress); bitStream->Serialize(writeToBitstream,serverSystemAddress);
bitStream->Serialize(writeToBitstream,clientSystemAddress); bitStream->Serialize(writeToBitstream,clientSystemAddress);
bitStream->Serialize(writeToBitstream,serverGUID); bitStream->Serialize(writeToBitstream,serverGUID);
bitStream->Serialize(writeToBitstream,clientGUID); bitStream->Serialize(writeToBitstream,clientGUID);
bitStream->Serialize(writeToBitstream,length); bitStream->Serialize(writeToBitstream,length);
if (writeToBitstream) if (writeToBitstream)
{ {
bitStream->WriteAlignedBytes((const unsigned char*) data,length); bitStream->WriteAlignedBytes((const unsigned char*) data,length);
} }
else else
{ {
if (length>0) if (length>0)
{ {
data = allocator->AllocateRowData(length); data = allocator->AllocateRowData(length);
if (data) if (data)
{ {
bitStream->ReadAlignedBytes((unsigned char *) data,length); bitStream->ReadAlignedBytes((unsigned char *) data,length);
} }
else else
{ {
notifyOutOfMemory(_FILE_AND_LINE_); notifyOutOfMemory(_FILE_AND_LINE_);
} }
} }
else else
data=0; data=0;
} }
} }
void CloudQueryResult::SerializeHeader(bool writeToBitstream, BitStream *bitStream) void CloudQueryResult::SerializeHeader(bool writeToBitstream, BitStream *bitStream)
{ {
cloudQuery.Serialize(writeToBitstream,bitStream); cloudQuery.Serialize(writeToBitstream,bitStream);
bitStream->Serialize(writeToBitstream,subscribeToResults); bitStream->Serialize(writeToBitstream,subscribeToResults);
} }
void CloudQueryResult::SerializeNumRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream) void CloudQueryResult::SerializeNumRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream)
{ {
bitStream->Serialize(writeToBitstream,numRows); bitStream->Serialize(writeToBitstream,numRows);
} }
void CloudQueryResult::SerializeCloudQueryRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream, CloudAllocator *allocator) void CloudQueryResult::SerializeCloudQueryRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream, CloudAllocator *allocator)
{ {
if (writeToBitstream) if (writeToBitstream)
{ {
for (uint16_t i=0; i < numRows; i++) for (uint16_t i=0; i < numRows; i++)
{ {
rowsReturned[i]->Serialize(true,bitStream, allocator); rowsReturned[i]->Serialize(true,bitStream, allocator);
} }
} }
else else
{ {
CloudQueryRow* cmdr; CloudQueryRow* cmdr;
for (uint16_t i=0; i < numRows; i++) for (uint16_t i=0; i < numRows; i++)
{ {
cmdr = allocator->AllocateCloudQueryRow(); cmdr = allocator->AllocateCloudQueryRow();
if (cmdr) if (cmdr)
{ {
cmdr->Serialize(false,bitStream,allocator); cmdr->Serialize(false,bitStream,allocator);
if (cmdr->data==0 && cmdr->length>0) if (cmdr->data==0 && cmdr->length>0)
{ {
allocator->DeallocateCloudQueryRow(cmdr); allocator->DeallocateCloudQueryRow(cmdr);
notifyOutOfMemory(_FILE_AND_LINE_); notifyOutOfMemory(_FILE_AND_LINE_);
numRows=i; numRows=i;
return; return;
} }
rowsReturned.Push(cmdr, _FILE_AND_LINE_); rowsReturned.Push(cmdr, _FILE_AND_LINE_);
} }
else else
{ {
notifyOutOfMemory(_FILE_AND_LINE_); notifyOutOfMemory(_FILE_AND_LINE_);
numRows=i; numRows=i;
return; return;
} }
} }
} }
} }
void CloudQueryResult::Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator) void CloudQueryResult::Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator)
{ {
SerializeHeader(writeToBitstream, bitStream); SerializeHeader(writeToBitstream, bitStream);
uint32_t numRows = (uint32_t) rowsReturned.Size(); uint32_t numRows = (uint32_t) rowsReturned.Size();
SerializeNumRows(writeToBitstream, numRows, bitStream); SerializeNumRows(writeToBitstream, numRows, bitStream);
SerializeCloudQueryRows(writeToBitstream, numRows, bitStream, allocator); SerializeCloudQueryRows(writeToBitstream, numRows, bitStream, allocator);
} }
#endif // #if _RAKNET_SUPPORT_CloudMemoryClient==1 || _RAKNET_SUPPORT_CloudMemoryServer==1 #endif // #if _RAKNET_SUPPORT_CloudMemoryClient==1 || _RAKNET_SUPPORT_CloudMemoryServer==1

View File

@@ -1,141 +1,141 @@
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_CloudClient==1 || _RAKNET_SUPPORT_CloudServer==1 #if _RAKNET_SUPPORT_CloudClient==1 || _RAKNET_SUPPORT_CloudServer==1
#ifndef __CLOUD_COMMON_H #ifndef __CLOUD_COMMON_H
#define __CLOUD_COMMON_H #define __CLOUD_COMMON_H
#include "RakNetTypes.h" #include "RakNetTypes.h"
#include "RakString.h" #include "RakString.h"
namespace RakNet namespace RakNet
{ {
class BitStream; class BitStream;
struct CloudQueryRow; struct CloudQueryRow;
/// Allocates CloudQueryRow and the row data. Override to use derived classes or different allocators /// Allocates CloudQueryRow and the row data. Override to use derived classes or different allocators
/// \ingroup CLOUD_GROUP /// \ingroup CLOUD_GROUP
class RAK_DLL_EXPORT CloudAllocator class RAK_DLL_EXPORT CloudAllocator
{ {
public: public:
CloudAllocator() {} CloudAllocator() {}
virtual ~CloudAllocator() {} virtual ~CloudAllocator() {}
/// \brief Allocate a row /// \brief Allocate a row
virtual CloudQueryRow* AllocateCloudQueryRow(void); virtual CloudQueryRow* AllocateCloudQueryRow(void);
/// \brief Free a row /// \brief Free a row
virtual void DeallocateCloudQueryRow(CloudQueryRow *row); virtual void DeallocateCloudQueryRow(CloudQueryRow *row);
/// \brief Allocate CloudQueryRow::data /// \brief Allocate CloudQueryRow::data
virtual unsigned char *AllocateRowData(uint32_t bytesNeededForData); virtual unsigned char *AllocateRowData(uint32_t bytesNeededForData);
/// \brief Free CloudQueryRow::data /// \brief Free CloudQueryRow::data
virtual void DeallocateRowData(void *data); virtual void DeallocateRowData(void *data);
}; };
/// Serves as a key to identify data uploaded to or queried from the server. /// Serves as a key to identify data uploaded to or queried from the server.
/// \ingroup CLOUD_GROUP /// \ingroup CLOUD_GROUP
struct RAK_DLL_EXPORT CloudKey struct RAK_DLL_EXPORT CloudKey
{ {
CloudKey() {} CloudKey() {}
CloudKey(RakNet::RakString _primaryKey, uint32_t _secondaryKey) : primaryKey(_primaryKey), secondaryKey(_secondaryKey) {} CloudKey(RakNet::RakString _primaryKey, uint32_t _secondaryKey) : primaryKey(_primaryKey), secondaryKey(_secondaryKey) {}
~CloudKey() {} ~CloudKey() {}
/// Identifies the primary key. This is intended to be a major category, such as the name of the application /// Identifies the primary key. This is intended to be a major category, such as the name of the application
/// Must be non-empty /// Must be non-empty
RakNet::RakString primaryKey; RakNet::RakString primaryKey;
/// Identifies the secondary key. This is intended to be a subcategory enumeration, such as PLAYER_LIST or RUNNING_SCORES /// Identifies the secondary key. This is intended to be a subcategory enumeration, such as PLAYER_LIST or RUNNING_SCORES
uint32_t secondaryKey; uint32_t secondaryKey;
/// \internal /// \internal
void Serialize(bool writeToBitstream, BitStream *bitStream); void Serialize(bool writeToBitstream, BitStream *bitStream);
}; };
/// \internal /// \internal
int CloudKeyComp(const CloudKey &key, const CloudKey &data); int CloudKeyComp(const CloudKey &key, const CloudKey &data);
/// Data members used to query the cloud /// Data members used to query the cloud
/// \ingroup CLOUD_GROUP /// \ingroup CLOUD_GROUP
struct RAK_DLL_EXPORT CloudQuery struct RAK_DLL_EXPORT CloudQuery
{ {
CloudQuery() {startingRowIndex=0; maxRowsToReturn=0; subscribeToResults=false;} CloudQuery() {startingRowIndex=0; maxRowsToReturn=0; subscribeToResults=false;}
/// List of keys to query. Must be at least of length 1. /// List of keys to query. Must be at least of length 1.
/// This query is run on uploads from all clients, and those that match the combination of primaryKey and secondaryKey are potentially returned /// This query is run on uploads from all clients, and those that match the combination of primaryKey and secondaryKey are potentially returned
/// If you pass more than one key at a time, the results are concatenated so if you need to differentiate between queries then send two different queries /// If you pass more than one key at a time, the results are concatenated so if you need to differentiate between queries then send two different queries
DataStructures::List<CloudKey> keys; DataStructures::List<CloudKey> keys;
/// If limiting the number of rows to return, this is the starting offset into the list. Has no effect unless maxRowsToReturn is > 0 /// If limiting the number of rows to return, this is the starting offset into the list. Has no effect unless maxRowsToReturn is > 0
uint32_t startingRowIndex; uint32_t startingRowIndex;
/// Maximum number of rows to return. Actual number may still be less than this. Pass 0 to mean no-limit. /// Maximum number of rows to return. Actual number may still be less than this. Pass 0 to mean no-limit.
uint32_t maxRowsToReturn; uint32_t maxRowsToReturn;
/// If true, automatically get updates as the results returned to you change. Unsubscribe with CloudMemoryClient::Unsubscribe() /// If true, automatically get updates as the results returned to you change. Unsubscribe with CloudMemoryClient::Unsubscribe()
bool subscribeToResults; bool subscribeToResults;
/// \internal /// \internal
void Serialize(bool writeToBitstream, BitStream *bitStream); void Serialize(bool writeToBitstream, BitStream *bitStream);
}; };
/// \ingroup CLOUD_GROUP /// \ingroup CLOUD_GROUP
struct RAK_DLL_EXPORT CloudQueryRow struct RAK_DLL_EXPORT CloudQueryRow
{ {
/// Key used to identify this data /// Key used to identify this data
CloudKey key; CloudKey key;
/// Data uploaded /// Data uploaded
unsigned char *data; unsigned char *data;
/// Length of data uploaded /// Length of data uploaded
uint32_t length; uint32_t length;
/// System address of server that is holding this data, and the client is connected to /// System address of server that is holding this data, and the client is connected to
SystemAddress serverSystemAddress; SystemAddress serverSystemAddress;
/// System address of client that uploaded this data /// System address of client that uploaded this data
SystemAddress clientSystemAddress; SystemAddress clientSystemAddress;
/// RakNetGUID of server that is holding this data, and the client is connected to /// RakNetGUID of server that is holding this data, and the client is connected to
RakNetGUID serverGUID; RakNetGUID serverGUID;
/// RakNetGUID of client that uploaded this data /// RakNetGUID of client that uploaded this data
RakNetGUID clientGUID; RakNetGUID clientGUID;
/// \internal /// \internal
void Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator); void Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator);
}; };
/// \ingroup CLOUD_GROUP /// \ingroup CLOUD_GROUP
struct RAK_DLL_EXPORT CloudQueryResult struct RAK_DLL_EXPORT CloudQueryResult
{ {
/// Query originally passed to Download() /// Query originally passed to Download()
CloudQuery cloudQuery; CloudQuery cloudQuery;
/// Results returned from query. If there were multiple keys in CloudQuery::keys then see resultKeyIndices /// Results returned from query. If there were multiple keys in CloudQuery::keys then see resultKeyIndices
DataStructures::List<CloudQueryRow*> rowsReturned; DataStructures::List<CloudQueryRow*> rowsReturned;
/// If there were multiple keys in CloudQuery::keys, then each key is processed in order and the result concatenated to rowsReturned /// If there were multiple keys in CloudQuery::keys, then each key is processed in order and the result concatenated to rowsReturned
/// The starting index of each query is written to resultKeyIndices /// The starting index of each query is written to resultKeyIndices
/// For example, if CloudQuery::keys had 4 keys, returning 3 rows, 0, rows, 5 rows, and 12 rows then /// For example, if CloudQuery::keys had 4 keys, returning 3 rows, 0, rows, 5 rows, and 12 rows then
/// resultKeyIndices would be 0, 3, 3, 8 /// resultKeyIndices would be 0, 3, 3, 8
DataStructures::List<uint32_t> resultKeyIndices; DataStructures::List<uint32_t> resultKeyIndices;
/// Whatever was passed to CloudClient::Get() as CloudQuery::subscribeToResults /// Whatever was passed to CloudClient::Get() as CloudQuery::subscribeToResults
bool subscribeToResults; bool subscribeToResults;
/// \internal /// \internal
void Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator); void Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator);
/// \internal /// \internal
void SerializeHeader(bool writeToBitstream, BitStream *bitStream); void SerializeHeader(bool writeToBitstream, BitStream *bitStream);
/// \internal /// \internal
void SerializeNumRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream); void SerializeNumRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream);
/// \internal /// \internal
void SerializeCloudQueryRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream, CloudAllocator *allocator); void SerializeCloudQueryRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream, CloudAllocator *allocator);
}; };
} // Namespace RakNet } // Namespace RakNet
#endif // __CLOUD_COMMON_H #endif // __CLOUD_COMMON_H
#endif // #if _RAKNET_SUPPORT_CloudClient==1 || _RAKNET_SUPPORT_CloudServer==1 #endif // #if _RAKNET_SUPPORT_CloudClient==1 || _RAKNET_SUPPORT_CloudServer==1

File diff suppressed because it is too large Load Diff

View File

@@ -1,375 +1,375 @@
/// \file CloudServer.h /// \file CloudServer.h
/// \brief Stores client data, and allows cross-server communication to retrieve this data /// \brief Stores client data, and allows cross-server communication to retrieve this data
/// \details TODO /// \details TODO
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_CloudServer==1 #if _RAKNET_SUPPORT_CloudServer==1
#ifndef __CLOUD_SERVER_H #ifndef __CLOUD_SERVER_H
#define __CLOUD_SERVER_H #define __CLOUD_SERVER_H
#include "PluginInterface2.h" #include "PluginInterface2.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "NativeTypes.h" #include "NativeTypes.h"
#include "RakString.h" #include "RakString.h"
#include "DS_Hash.h" #include "DS_Hash.h"
#include "CloudCommon.h" #include "CloudCommon.h"
#include "DS_OrderedList.h" #include "DS_OrderedList.h"
/// If the data is smaller than this value, an allocation is avoid. However, this value exists for every row /// If the data is smaller than this value, an allocation is avoid. However, this value exists for every row
#define CLOUD_SERVER_DATA_STACK_SIZE 32 #define CLOUD_SERVER_DATA_STACK_SIZE 32
namespace RakNet namespace RakNet
{ {
/// Forward declarations /// Forward declarations
class RakPeerInterface; class RakPeerInterface;
/// \brief Zero or more instances of CloudServerQueryFilter can be attached to CloudServer to restrict client queries /// \brief Zero or more instances of CloudServerQueryFilter can be attached to CloudServer to restrict client queries
/// All attached instances of CloudServerQueryFilter on each corresponding operation, from all directly connected clients /// All attached instances of CloudServerQueryFilter on each corresponding operation, from all directly connected clients
/// If any attached instance returns false for a given operation, that operation is silently rejected /// If any attached instance returns false for a given operation, that operation is silently rejected
/// \ingroup CLOUD_GROUP /// \ingroup CLOUD_GROUP
class RAK_DLL_EXPORT CloudServerQueryFilter class RAK_DLL_EXPORT CloudServerQueryFilter
{ {
public: public:
CloudServerQueryFilter() {} CloudServerQueryFilter() {}
virtual ~CloudServerQueryFilter() {} virtual ~CloudServerQueryFilter() {}
/// Called when a local client wants to post data /// Called when a local client wants to post data
/// \return true to allow, false to reject /// \return true to allow, false to reject
virtual bool OnPostRequest(RakNetGUID clientGuid, SystemAddress clientAddress, CloudKey key, uint32_t dataLength, const char *data)=0; virtual bool OnPostRequest(RakNetGUID clientGuid, SystemAddress clientAddress, CloudKey key, uint32_t dataLength, const char *data)=0;
/// Called when a local client wants to release data that it has previously uploaded /// Called when a local client wants to release data that it has previously uploaded
/// \return true to allow, false to reject /// \return true to allow, false to reject
virtual bool OnReleaseRequest(RakNetGUID clientGuid, SystemAddress clientAddress, DataStructures::List<CloudKey> &cloudKeys)=0; virtual bool OnReleaseRequest(RakNetGUID clientGuid, SystemAddress clientAddress, DataStructures::List<CloudKey> &cloudKeys)=0;
/// Called when a local client wants to query data /// Called when a local client wants to query data
/// If you return false, the client will get no response at all /// If you return false, the client will get no response at all
/// \return true to allow, false to reject /// \return true to allow, false to reject
virtual bool OnGetRequest(RakNetGUID clientGuid, SystemAddress clientAddress, CloudQuery &query, DataStructures::List<RakNetGUID> &specificSystems)=0; virtual bool OnGetRequest(RakNetGUID clientGuid, SystemAddress clientAddress, CloudQuery &query, DataStructures::List<RakNetGUID> &specificSystems)=0;
/// Called when a local client wants to stop getting updates for data /// Called when a local client wants to stop getting updates for data
/// If you return false, the client will keep getting updates for that data /// If you return false, the client will keep getting updates for that data
/// \return true to allow, false to reject /// \return true to allow, false to reject
virtual bool OnUnsubscribeRequest(RakNetGUID clientGuid, SystemAddress clientAddress, DataStructures::List<CloudKey> &cloudKeys, DataStructures::List<RakNetGUID> &specificSystems)=0; virtual bool OnUnsubscribeRequest(RakNetGUID clientGuid, SystemAddress clientAddress, DataStructures::List<CloudKey> &cloudKeys, DataStructures::List<RakNetGUID> &specificSystems)=0;
}; };
/// \brief Stores client data, and allows cross-server communication to retrieve this data /// \brief Stores client data, and allows cross-server communication to retrieve this data
/// \ingroup CLOUD_GROUP /// \ingroup CLOUD_GROUP
class RAK_DLL_EXPORT CloudServer : public PluginInterface2, CloudAllocator class RAK_DLL_EXPORT CloudServer : public PluginInterface2, CloudAllocator
{ {
public: public:
// GetInstance() and DestroyInstance(instance*) // GetInstance() and DestroyInstance(instance*)
STATIC_FACTORY_DECLARATIONS(CloudServer) STATIC_FACTORY_DECLARATIONS(CloudServer)
CloudServer(); CloudServer();
virtual ~CloudServer(); virtual ~CloudServer();
/// \brief Max bytes a client can upload /// \brief Max bytes a client can upload
/// Data in excess of this value is silently ignored /// Data in excess of this value is silently ignored
/// defaults to 0 (unlimited) /// defaults to 0 (unlimited)
/// \param[in] bytes Max bytes a client can upload. 0 means unlimited. /// \param[in] bytes Max bytes a client can upload. 0 means unlimited.
void SetMaxUploadBytesPerClient(uint64_t bytes); void SetMaxUploadBytesPerClient(uint64_t bytes);
/// \brief Max bytes returned by a download. If the number of bytes would exceed this amount, the returned list is truncated /// \brief Max bytes returned by a download. If the number of bytes would exceed this amount, the returned list is truncated
/// However, if this would result in no rows downloaded, then one row will be returned. /// However, if this would result in no rows downloaded, then one row will be returned.
/// \param[in] bytes Max bytes a client can download from a single Get(). 0 means unlimited. /// \param[in] bytes Max bytes a client can download from a single Get(). 0 means unlimited.
void SetMaxBytesPerDownload(uint64_t bytes); void SetMaxBytesPerDownload(uint64_t bytes);
/// \brief Add a server, which is assumed to be connected in a fully connected mesh to all other servers and also running the CloudServer plugin /// \brief Add a server, which is assumed to be connected in a fully connected mesh to all other servers and also running the CloudServer plugin
/// The other system must also call AddServer before getting the subscription data, or it will be rejected. /// The other system must also call AddServer before getting the subscription data, or it will be rejected.
/// Sending a message telling the other system to call AddServer(), followed by calling AddServer() locally, would be sufficient for this to work. /// Sending a message telling the other system to call AddServer(), followed by calling AddServer() locally, would be sufficient for this to work.
/// \note This sends subscription data to the other system, using RELIABLE_ORDERED on channel 0 /// \note This sends subscription data to the other system, using RELIABLE_ORDERED on channel 0
/// \param[in] systemIdentifier Identifier of the remote system /// \param[in] systemIdentifier Identifier of the remote system
void AddServer(RakNetGUID systemIdentifier); void AddServer(RakNetGUID systemIdentifier);
/// \brief Removes a server added through AddServer() /// \brief Removes a server added through AddServer()
/// \param[in] systemIdentifier Identifier of the remote system /// \param[in] systemIdentifier Identifier of the remote system
void RemoveServer(RakNetGUID systemIdentifier); void RemoveServer(RakNetGUID systemIdentifier);
/// Return list of servers added with AddServer() /// Return list of servers added with AddServer()
/// \param[out] remoteServers List of servers added /// \param[out] remoteServers List of servers added
void GetRemoteServers(DataStructures::List<RakNetGUID> &remoteServersOut); void GetRemoteServers(DataStructures::List<RakNetGUID> &remoteServersOut);
/// \brief Frees all memory. Does not remove query filters /// \brief Frees all memory. Does not remove query filters
void Clear(void); void Clear(void);
/// \brief Report the specified SystemAddress to client queries, rather than what RakPeer reads. /// \brief Report the specified SystemAddress to client queries, rather than what RakPeer reads.
/// This is useful if you already know your public IP /// This is useful if you already know your public IP
/// This only applies to future updates, so call it before updating to apply to all queries /// This only applies to future updates, so call it before updating to apply to all queries
/// \param[in] forcedAddress The systmeAddress to return in queries. Use UNASSIGNED_SYSTEM_ADDRESS (default) to use what RakPeer returns /// \param[in] forcedAddress The systmeAddress to return in queries. Use UNASSIGNED_SYSTEM_ADDRESS (default) to use what RakPeer returns
void ForceExternalSystemAddress(SystemAddress forcedAddress); void ForceExternalSystemAddress(SystemAddress forcedAddress);
/// \brief Adds a callback called on each query. If all filters returns true for an operation, the operation is allowed. /// \brief Adds a callback called on each query. If all filters returns true for an operation, the operation is allowed.
/// If the filter was already added, the function silently fails /// If the filter was already added, the function silently fails
/// \param[in] filter An externally allocated instance of CloudServerQueryFilter. The instance must remain valid until it is removed with RemoveQueryFilter() or RemoveAllQueryFilters() /// \param[in] filter An externally allocated instance of CloudServerQueryFilter. The instance must remain valid until it is removed with RemoveQueryFilter() or RemoveAllQueryFilters()
void AddQueryFilter(CloudServerQueryFilter* filter); void AddQueryFilter(CloudServerQueryFilter* filter);
/// \brief Removes a callback added with AddQueryFilter() /// \brief Removes a callback added with AddQueryFilter()
/// The instance is not deleted, only unreferenced. It is up to the user to delete the instance, if necessary /// The instance is not deleted, only unreferenced. It is up to the user to delete the instance, if necessary
/// \param[in] filter An externally allocated instance of CloudServerQueryFilter. The instance must remain valid until it is removed with RemoveQueryFilter() or RemoveAllQueryFilters() /// \param[in] filter An externally allocated instance of CloudServerQueryFilter. The instance must remain valid until it is removed with RemoveQueryFilter() or RemoveAllQueryFilters()
void RemoveQueryFilter(CloudServerQueryFilter* filter); void RemoveQueryFilter(CloudServerQueryFilter* filter);
/// \brief Removes all instances of CloudServerQueryFilter added with AddQueryFilter(). /// \brief Removes all instances of CloudServerQueryFilter added with AddQueryFilter().
/// The instances are not deleted, only unreferenced. It is up to the user to delete the instances, if necessary /// The instances are not deleted, only unreferenced. It is up to the user to delete the instances, if necessary
void RemoveAllQueryFilters(void); void RemoveAllQueryFilters(void);
protected: protected:
virtual void Update(void); virtual void Update(void);
virtual PluginReceiveResult OnReceive(Packet *packet); virtual PluginReceiveResult OnReceive(Packet *packet);
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason ); virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
virtual void OnRakPeerShutdown(void); virtual void OnRakPeerShutdown(void);
virtual void OnPostRequest(Packet *packet); virtual void OnPostRequest(Packet *packet);
virtual void OnReleaseRequest(Packet *packet); virtual void OnReleaseRequest(Packet *packet);
virtual void OnGetRequest(Packet *packet); virtual void OnGetRequest(Packet *packet);
virtual void OnUnsubscribeRequest(Packet *packet); virtual void OnUnsubscribeRequest(Packet *packet);
virtual void OnServerToServerGetRequest(Packet *packet); virtual void OnServerToServerGetRequest(Packet *packet);
virtual void OnServerToServerGetResponse(Packet *packet); virtual void OnServerToServerGetResponse(Packet *packet);
uint64_t maxUploadBytesPerClient, maxBytesPerDowload; uint64_t maxUploadBytesPerClient, maxBytesPerDowload;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// For a given data key, quickly look up one or all systems that have uploaded // For a given data key, quickly look up one or all systems that have uploaded
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
struct CloudData struct CloudData
{ {
CloudData() {} CloudData() {}
~CloudData() {if (allocatedData) rakFree_Ex(allocatedData, _FILE_AND_LINE_);} ~CloudData() {if (allocatedData) rakFree_Ex(allocatedData, _FILE_AND_LINE_);}
bool IsUnused(void) const {return isUploaded==false && specificSubscribers.Size()==0;} bool IsUnused(void) const {return isUploaded==false && specificSubscribers.Size()==0;}
void Clear(void) {if (dataPtr==allocatedData) rakFree_Ex(allocatedData, _FILE_AND_LINE_); allocatedData=0; dataPtr=0; dataLengthBytes=0; isUploaded=false;} void Clear(void) {if (dataPtr==allocatedData) rakFree_Ex(allocatedData, _FILE_AND_LINE_); allocatedData=0; dataPtr=0; dataLengthBytes=0; isUploaded=false;}
unsigned char stackData[CLOUD_SERVER_DATA_STACK_SIZE]; unsigned char stackData[CLOUD_SERVER_DATA_STACK_SIZE];
unsigned char *allocatedData; // Uses allocatedData instead of stackData if length of data exceeds CLOUD_SERVER_DATA_STACK_SIZE unsigned char *allocatedData; // Uses allocatedData instead of stackData if length of data exceeds CLOUD_SERVER_DATA_STACK_SIZE
unsigned char *dataPtr; // Points to either stackData or allocatedData unsigned char *dataPtr; // Points to either stackData or allocatedData
uint32_t dataLengthBytes; uint32_t dataLengthBytes;
bool isUploaded; bool isUploaded;
/// System address of server that is holding this data, and the client is connected to /// System address of server that is holding this data, and the client is connected to
SystemAddress serverSystemAddress; SystemAddress serverSystemAddress;
/// System address of client that uploaded this data /// System address of client that uploaded this data
SystemAddress clientSystemAddress; SystemAddress clientSystemAddress;
/// RakNetGUID of server that is holding this data, and the client is connected to /// RakNetGUID of server that is holding this data, and the client is connected to
RakNetGUID serverGUID; RakNetGUID serverGUID;
/// RakNetGUID of client that uploaded this data /// RakNetGUID of client that uploaded this data
RakNetGUID clientGUID; RakNetGUID clientGUID;
/// When the key data changes from this particular system, notify these subscribers /// When the key data changes from this particular system, notify these subscribers
/// This list mutually exclusive with CloudDataList::nonSpecificSubscribers /// This list mutually exclusive with CloudDataList::nonSpecificSubscribers
DataStructures::OrderedList<RakNetGUID, RakNetGUID> specificSubscribers; DataStructures::OrderedList<RakNetGUID, RakNetGUID> specificSubscribers;
}; };
void WriteCloudQueryRowFromResultList(unsigned int i, DataStructures::List<CloudData*> &cloudDataResultList, DataStructures::List<CloudKey> &cloudKeyResultList, BitStream *bsOut); void WriteCloudQueryRowFromResultList(unsigned int i, DataStructures::List<CloudData*> &cloudDataResultList, DataStructures::List<CloudKey> &cloudKeyResultList, BitStream *bsOut);
void WriteCloudQueryRowFromResultList(DataStructures::List<CloudData*> &cloudDataResultList, DataStructures::List<CloudKey> &cloudKeyResultList, BitStream *bsOut); void WriteCloudQueryRowFromResultList(DataStructures::List<CloudData*> &cloudDataResultList, DataStructures::List<CloudKey> &cloudKeyResultList, BitStream *bsOut);
static int KeyDataPtrComp( const RakNetGUID &key, CloudData* const &data ); static int KeyDataPtrComp( const RakNetGUID &key, CloudData* const &data );
struct CloudDataList struct CloudDataList
{ {
bool IsUnused(void) const {return keyData.Size()==0 && nonSpecificSubscribers.Size()==0;} bool IsUnused(void) const {return keyData.Size()==0 && nonSpecificSubscribers.Size()==0;}
bool IsNotUploaded(void) const {return uploaderCount==0;} bool IsNotUploaded(void) const {return uploaderCount==0;}
bool RemoveSubscriber(RakNetGUID g) { bool RemoveSubscriber(RakNetGUID g) {
bool objectExists; bool objectExists;
unsigned int index; unsigned int index;
index = nonSpecificSubscribers.GetIndexFromKey(g, &objectExists); index = nonSpecificSubscribers.GetIndexFromKey(g, &objectExists);
if (objectExists) if (objectExists)
{ {
subscriberCount--; subscriberCount--;
nonSpecificSubscribers.RemoveAtIndex(index); nonSpecificSubscribers.RemoveAtIndex(index);
return true; return true;
} }
return false; return false;
} }
unsigned int uploaderCount, subscriberCount; unsigned int uploaderCount, subscriberCount;
CloudKey key; CloudKey key;
// Data uploaded from or subscribed to for various systems // Data uploaded from or subscribed to for various systems
DataStructures::OrderedList<RakNetGUID, CloudData*, CloudServer::KeyDataPtrComp> keyData; DataStructures::OrderedList<RakNetGUID, CloudData*, CloudServer::KeyDataPtrComp> keyData;
/// When the key data changes from any system, notify these subscribers /// When the key data changes from any system, notify these subscribers
/// This list mutually exclusive with CloudData::specificSubscribers /// This list mutually exclusive with CloudData::specificSubscribers
DataStructures::OrderedList<RakNetGUID, RakNetGUID> nonSpecificSubscribers; DataStructures::OrderedList<RakNetGUID, RakNetGUID> nonSpecificSubscribers;
}; };
static int KeyDataListComp( const CloudKey &key, CloudDataList * const &data ); static int KeyDataListComp( const CloudKey &key, CloudDataList * const &data );
DataStructures::OrderedList<CloudKey, CloudDataList*, CloudServer::KeyDataListComp> dataRepository; DataStructures::OrderedList<CloudKey, CloudDataList*, CloudServer::KeyDataListComp> dataRepository;
struct KeySubscriberID struct KeySubscriberID
{ {
CloudKey key; CloudKey key;
DataStructures::OrderedList<RakNetGUID, RakNetGUID> specificSystemsSubscribedTo; DataStructures::OrderedList<RakNetGUID, RakNetGUID> specificSystemsSubscribedTo;
}; };
static int KeySubscriberIDComp(const CloudKey &key, KeySubscriberID * const &data ); static int KeySubscriberIDComp(const CloudKey &key, KeySubscriberID * const &data );
// Remote systems // Remote systems
struct RemoteCloudClient struct RemoteCloudClient
{ {
bool IsUnused(void) const {return uploadedKeys.Size()==0 && subscribedKeys.Size()==0;} bool IsUnused(void) const {return uploadedKeys.Size()==0 && subscribedKeys.Size()==0;}
DataStructures::OrderedList<CloudKey,CloudKey,CloudKeyComp> uploadedKeys; DataStructures::OrderedList<CloudKey,CloudKey,CloudKeyComp> uploadedKeys;
DataStructures::OrderedList<CloudKey,KeySubscriberID*,CloudServer::KeySubscriberIDComp> subscribedKeys; DataStructures::OrderedList<CloudKey,KeySubscriberID*,CloudServer::KeySubscriberIDComp> subscribedKeys;
uint64_t uploadedBytes; uint64_t uploadedBytes;
}; };
DataStructures::Hash<RakNetGUID, RemoteCloudClient*, 2048, RakNetGUID::ToUint32> remoteSystems; DataStructures::Hash<RakNetGUID, RemoteCloudClient*, 2048, RakNetGUID::ToUint32> remoteSystems;
// For a given user, release all subscribed and uploaded keys // For a given user, release all subscribed and uploaded keys
void ReleaseSystem(RakNetGUID clientAddress ); void ReleaseSystem(RakNetGUID clientAddress );
// For a given user, release a set of keys // For a given user, release a set of keys
void ReleaseKeys(RakNetGUID clientAddress, DataStructures::List<CloudKey> &keys ); void ReleaseKeys(RakNetGUID clientAddress, DataStructures::List<CloudKey> &keys );
void NotifyClientSubscribersOfDataChange( CloudData *cloudData, CloudKey &key, DataStructures::OrderedList<RakNetGUID, RakNetGUID> &subscribers, bool wasUpdated ); void NotifyClientSubscribersOfDataChange( CloudData *cloudData, CloudKey &key, DataStructures::OrderedList<RakNetGUID, RakNetGUID> &subscribers, bool wasUpdated );
void NotifyClientSubscribersOfDataChange( CloudQueryRow *row, DataStructures::OrderedList<RakNetGUID, RakNetGUID> &subscribers, bool wasUpdated ); void NotifyClientSubscribersOfDataChange( CloudQueryRow *row, DataStructures::OrderedList<RakNetGUID, RakNetGUID> &subscribers, bool wasUpdated );
void NotifyServerSubscribersOfDataChange( CloudData *cloudData, CloudKey &key, bool wasUpdated ); void NotifyServerSubscribersOfDataChange( CloudData *cloudData, CloudKey &key, bool wasUpdated );
struct RemoteServer struct RemoteServer
{ {
RakNetGUID serverAddress; RakNetGUID serverAddress;
// This server needs to know about these keys when they are updated or deleted // This server needs to know about these keys when they are updated or deleted
DataStructures::OrderedList<CloudKey,CloudKey,CloudKeyComp> subscribedKeys; DataStructures::OrderedList<CloudKey,CloudKey,CloudKeyComp> subscribedKeys;
// This server has uploaded these keys, and needs to know about Get() requests // This server has uploaded these keys, and needs to know about Get() requests
DataStructures::OrderedList<CloudKey,CloudKey,CloudKeyComp> uploadedKeys; DataStructures::OrderedList<CloudKey,CloudKey,CloudKeyComp> uploadedKeys;
// Just for processing // Just for processing
bool workingFlag; bool workingFlag;
// If false, we don't know what keys they have yet, so send everything // If false, we don't know what keys they have yet, so send everything
bool gotSubscribedAndUploadedKeys; bool gotSubscribedAndUploadedKeys;
}; };
static int RemoteServerComp(const RakNetGUID &key, RemoteServer* const &data ); static int RemoteServerComp(const RakNetGUID &key, RemoteServer* const &data );
DataStructures::OrderedList<RakNetGUID, RemoteServer*, CloudServer::RemoteServerComp> remoteServers; DataStructures::OrderedList<RakNetGUID, RemoteServer*, CloudServer::RemoteServerComp> remoteServers;
struct BufferedGetResponseFromServer struct BufferedGetResponseFromServer
{ {
void Clear(CloudAllocator *allocator); void Clear(CloudAllocator *allocator);
RakNetGUID serverAddress; RakNetGUID serverAddress;
CloudQueryResult queryResult; CloudQueryResult queryResult;
bool gotResult; bool gotResult;
}; };
struct CloudQueryWithAddresses struct CloudQueryWithAddresses
{ {
// Inputs // Inputs
CloudQuery cloudQuery; CloudQuery cloudQuery;
DataStructures::List<RakNetGUID> specificSystems; DataStructures::List<RakNetGUID> specificSystems;
void Serialize(bool writeToBitstream, BitStream *bitStream); void Serialize(bool writeToBitstream, BitStream *bitStream);
}; };
static int BufferedGetResponseFromServerComp(const RakNetGUID &key, BufferedGetResponseFromServer* const &data ); static int BufferedGetResponseFromServerComp(const RakNetGUID &key, BufferedGetResponseFromServer* const &data );
struct GetRequest struct GetRequest
{ {
void Clear(CloudAllocator *allocator); void Clear(CloudAllocator *allocator);
bool AllRemoteServersHaveResponded(void) const; bool AllRemoteServersHaveResponded(void) const;
CloudQueryWithAddresses cloudQueryWithAddresses; CloudQueryWithAddresses cloudQueryWithAddresses;
// When request started. If takes too long for a response from another system, can abort remaining systems // When request started. If takes too long for a response from another system, can abort remaining systems
RakNet::Time requestStartTime; RakNet::Time requestStartTime;
// Assigned by server that gets the request to identify response. See nextGetRequestId // Assigned by server that gets the request to identify response. See nextGetRequestId
uint32_t requestId; uint32_t requestId;
RakNetGUID requestingClient; RakNetGUID requestingClient;
DataStructures::OrderedList<RakNetGUID, BufferedGetResponseFromServer*, CloudServer::BufferedGetResponseFromServerComp> remoteServerResponses; DataStructures::OrderedList<RakNetGUID, BufferedGetResponseFromServer*, CloudServer::BufferedGetResponseFromServerComp> remoteServerResponses;
}; };
static int GetRequestComp(const uint32_t &key, GetRequest* const &data ); static int GetRequestComp(const uint32_t &key, GetRequest* const &data );
DataStructures::OrderedList<uint32_t, GetRequest*, CloudServer::GetRequestComp> getRequests; DataStructures::OrderedList<uint32_t, GetRequest*, CloudServer::GetRequestComp> getRequests;
RakNet::Time nextGetRequestsCheck; RakNet::Time nextGetRequestsCheck;
uint32_t nextGetRequestId; uint32_t nextGetRequestId;
void ProcessAndTransmitGetRequest(GetRequest *getRequest); void ProcessAndTransmitGetRequest(GetRequest *getRequest);
void ProcessCloudQueryWithAddresses( void ProcessCloudQueryWithAddresses(
CloudServer::CloudQueryWithAddresses &cloudQueryWithAddresses, CloudServer::CloudQueryWithAddresses &cloudQueryWithAddresses,
DataStructures::List<CloudData*> &cloudDataResultList, DataStructures::List<CloudData*> &cloudDataResultList,
DataStructures::List<CloudKey> &cloudKeyResultList DataStructures::List<CloudKey> &cloudKeyResultList
); );
void SendUploadedAndSubscribedKeysToServer( RakNetGUID systemAddress ); void SendUploadedAndSubscribedKeysToServer( RakNetGUID systemAddress );
void SendUploadedKeyToServers( CloudKey &cloudKey ); void SendUploadedKeyToServers( CloudKey &cloudKey );
void SendSubscribedKeyToServers( CloudKey &cloudKey ); void SendSubscribedKeyToServers( CloudKey &cloudKey );
void RemoveUploadedKeyFromServers( CloudKey &cloudKey ); void RemoveUploadedKeyFromServers( CloudKey &cloudKey );
void RemoveSubscribedKeyFromServers( CloudKey &cloudKey ); void RemoveSubscribedKeyFromServers( CloudKey &cloudKey );
void OnSendUploadedAndSubscribedKeysToServer( Packet *packet ); void OnSendUploadedAndSubscribedKeysToServer( Packet *packet );
void OnSendUploadedKeyToServers( Packet *packet ); void OnSendUploadedKeyToServers( Packet *packet );
void OnSendSubscribedKeyToServers( Packet *packet ); void OnSendSubscribedKeyToServers( Packet *packet );
void OnRemoveUploadedKeyFromServers( Packet *packet ); void OnRemoveUploadedKeyFromServers( Packet *packet );
void OnRemoveSubscribedKeyFromServers( Packet *packet ); void OnRemoveSubscribedKeyFromServers( Packet *packet );
void OnServerDataChanged( Packet *packet ); void OnServerDataChanged( Packet *packet );
void GetServersWithUploadedKeys( void GetServersWithUploadedKeys(
DataStructures::List<CloudKey> &keys, DataStructures::List<CloudKey> &keys,
DataStructures::List<RemoteServer*> &remoteServersWithData DataStructures::List<RemoteServer*> &remoteServersWithData
); );
CloudServer::CloudDataList *GetOrAllocateCloudDataList(CloudKey key, bool *dataRepositoryExists, unsigned int &dataRepositoryIndex); CloudServer::CloudDataList *GetOrAllocateCloudDataList(CloudKey key, bool *dataRepositoryExists, unsigned int &dataRepositoryIndex);
void UnsubscribeFromKey(RemoteCloudClient *remoteCloudClient, RakNetGUID remoteCloudClientGuid, unsigned int keySubscriberIndex, CloudKey &cloudKey, DataStructures::List<RakNetGUID> &specificSystems); void UnsubscribeFromKey(RemoteCloudClient *remoteCloudClient, RakNetGUID remoteCloudClientGuid, unsigned int keySubscriberIndex, CloudKey &cloudKey, DataStructures::List<RakNetGUID> &specificSystems);
void RemoveSpecificSubscriber(RakNetGUID specificSubscriber, CloudDataList *cloudDataList, RakNetGUID remoteCloudClientGuid); void RemoveSpecificSubscriber(RakNetGUID specificSubscriber, CloudDataList *cloudDataList, RakNetGUID remoteCloudClientGuid);
DataStructures::List<CloudServerQueryFilter*> queryFilters; DataStructures::List<CloudServerQueryFilter*> queryFilters;
SystemAddress forceAddress; SystemAddress forceAddress;
}; };
} // namespace RakNet } // namespace RakNet
#endif #endif
// Key subscription // Key subscription
// //
// A given system can subscribe to one or more keys. // A given system can subscribe to one or more keys.
// The subscription can be further be defined as only subscribing to keys uploaded by or changed by a given system. // The subscription can be further be defined as only subscribing to keys uploaded by or changed by a given system.
// It is possible to subscribe to keys not yet uploaded, or uploaded to another system // It is possible to subscribe to keys not yet uploaded, or uploaded to another system
// //
// Operations: // Operations:
// //
// 1. SubscribeToKey() - Get() operation with subscription // 1. SubscribeToKey() - Get() operation with subscription
// A. Add to key subscription list for the client, which contains a keyId / specificUploaderList pair // A. Add to key subscription list for the client, which contains a keyId / specificUploaderList pair
// B. Send to remote servers that for this key, they should send us updates // B. Send to remote servers that for this key, they should send us updates
// C. (Done, get operation returns current values) // C. (Done, get operation returns current values)
// //
// 2. UpdateData() - Post() operation // 2. UpdateData() - Post() operation
// A. Find all subscribers to this data, for the uploading system. // A. Find all subscribers to this data, for the uploading system.
// B. Send them the uploaded data // B. Send them the uploaded data
// C. Find all servers that subscribe to this data // C. Find all servers that subscribe to this data
// D. Send them the uploaded data // D. Send them the uploaded data
// //
// 3. DeleteData() - Release() operation // 3. DeleteData() - Release() operation
// A. Find all subscribers to this data, for the deleting system. // A. Find all subscribers to this data, for the deleting system.
// B. Inform them of the deletion // B. Inform them of the deletion
// C. Find all servers that subscribe to this data // C. Find all servers that subscribe to this data
// D. Inform them of the deletion // D. Inform them of the deletion
// //
// 4. Unsubscribe() // 4. Unsubscribe()
// A. Find this subscriber, and remove their subscription // A. Find this subscriber, and remove their subscription
// B. If no one else is subscribing to this key for any system, notify remote servers we no longer need subscription updates // B. If no one else is subscribing to this key for any system, notify remote servers we no longer need subscription updates
// //
// Internal operations: // Internal operations:
// //
// 1. Find if any connected client has subscribed to a given key // 1. Find if any connected client has subscribed to a given key
// A. This is used add and remove our subscription for this key to remote servers // A. This is used add and remove our subscription for this key to remote servers
// //
// 2. For a given key and updating address, find all connected clients that care // 2. For a given key and updating address, find all connected clients that care
// A. First find connected clients that have subscribed to this key, regardless of address // A. First find connected clients that have subscribed to this key, regardless of address
// B. Then find connected clients that have subscribed to this key for this particular address // B. Then find connected clients that have subscribed to this key for this particular address
// //
// 3. Find all remote servers that have subscribed to a given key // 3. Find all remote servers that have subscribed to a given key
// A. This is so when the key is updated or deleted, we know who to send it to // A. This is so when the key is updated or deleted, we know who to send it to
// //
// 4. For a given client (such as on disconnect), remove all records of their subscriptions // 4. For a given client (such as on disconnect), remove all records of their subscriptions
#endif // _RAKNET_SUPPORT_* #endif // _RAKNET_SUPPORT_*

View File

@@ -1,161 +1,161 @@
#include "CommandParserInterface.h" #include "CommandParserInterface.h"
#include "TransportInterface.h" #include "TransportInterface.h"
#include <string.h> #include <string.h>
#include "RakAssert.h" #include "RakAssert.h"
#include <stdio.h> #include <stdio.h>
#if defined(_WIN32) #if defined(_WIN32)
// IP_DONTFRAGMENT is different between winsock 1 and winsock 2. Therefore, Winsock2.h must be linked againt Ws2_32.lib // IP_DONTFRAGMENT is different between winsock 1 and winsock 2. Therefore, Winsock2.h must be linked againt Ws2_32.lib
// winsock.h must be linked against WSock32.lib. If these two are mixed up the flag won't work correctly // winsock.h must be linked against WSock32.lib. If these two are mixed up the flag won't work correctly
#include <winsock2.h> #include <winsock2.h>
#else #else
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#include "LinuxStrings.h" #include "LinuxStrings.h"
using namespace RakNet; using namespace RakNet;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( push ) #pragma warning( push )
#endif #endif
const unsigned char CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS=255; const unsigned char CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS=255;
int RakNet::RegisteredCommandComp( const char* const & key, const RegisteredCommand &data ) int RakNet::RegisteredCommandComp( const char* const & key, const RegisteredCommand &data )
{ {
return _stricmp(key,data.command); return _stricmp(key,data.command);
} }
CommandParserInterface::CommandParserInterface() {} CommandParserInterface::CommandParserInterface() {}
CommandParserInterface::~CommandParserInterface() {} CommandParserInterface::~CommandParserInterface() {}
void CommandParserInterface::ParseConsoleString(char *str, const char delineator, unsigned char delineatorToggle, unsigned *numParameters, char **parameterList, unsigned parameterListLength) void CommandParserInterface::ParseConsoleString(char *str, const char delineator, unsigned char delineatorToggle, unsigned *numParameters, char **parameterList, unsigned parameterListLength)
{ {
unsigned strIndex, parameterListIndex; unsigned strIndex, parameterListIndex;
unsigned strLen; unsigned strLen;
bool replaceDelineator=true; bool replaceDelineator=true;
strLen = (unsigned) strlen(str); strLen = (unsigned) strlen(str);
// Replace every instance of delineator, \n, \r with 0 // Replace every instance of delineator, \n, \r with 0
for (strIndex=0; strIndex < strLen; strIndex++) for (strIndex=0; strIndex < strLen; strIndex++)
{ {
if (str[strIndex]==delineator && replaceDelineator) if (str[strIndex]==delineator && replaceDelineator)
str[strIndex]=0; str[strIndex]=0;
if (str[strIndex]=='\n' || str[strIndex]=='\r') if (str[strIndex]=='\n' || str[strIndex]=='\r')
str[strIndex]=0; str[strIndex]=0;
if (str[strIndex]==delineatorToggle) if (str[strIndex]==delineatorToggle)
{ {
str[strIndex]=0; str[strIndex]=0;
replaceDelineator=!replaceDelineator; replaceDelineator=!replaceDelineator;
} }
} }
// Fill up parameterList starting at each non-0 // Fill up parameterList starting at each non-0
for (strIndex=0, parameterListIndex=0; strIndex < strLen; ) for (strIndex=0, parameterListIndex=0; strIndex < strLen; )
{ {
if (str[strIndex]!=0) if (str[strIndex]!=0)
{ {
parameterList[parameterListIndex]=str+strIndex; parameterList[parameterListIndex]=str+strIndex;
parameterListIndex++; parameterListIndex++;
RakAssert(parameterListIndex < parameterListLength); RakAssert(parameterListIndex < parameterListLength);
if (parameterListIndex >= parameterListLength) if (parameterListIndex >= parameterListLength)
break; break;
strIndex++; strIndex++;
while (str[strIndex]!=0 && strIndex < strLen) while (str[strIndex]!=0 && strIndex < strLen)
strIndex++; strIndex++;
} }
else else
strIndex++; strIndex++;
} }
parameterList[parameterListIndex]=0; parameterList[parameterListIndex]=0;
*numParameters=parameterListIndex; *numParameters=parameterListIndex;
} }
void CommandParserInterface::SendCommandList(TransportInterface *transport, const SystemAddress &systemAddress) void CommandParserInterface::SendCommandList(TransportInterface *transport, const SystemAddress &systemAddress)
{ {
unsigned i; unsigned i;
if (commandList.Size()) if (commandList.Size())
{ {
for (i=0; i < commandList.Size(); i++) for (i=0; i < commandList.Size(); i++)
{ {
transport->Send(systemAddress, "%s", commandList[i].command); transport->Send(systemAddress, "%s", commandList[i].command);
if (i < commandList.Size()-1) if (i < commandList.Size()-1)
transport->Send(systemAddress, ", "); transport->Send(systemAddress, ", ");
} }
transport->Send(systemAddress, "\r\n"); transport->Send(systemAddress, "\r\n");
} }
else else
transport->Send(systemAddress, "No registered commands\r\n"); transport->Send(systemAddress, "No registered commands\r\n");
} }
void CommandParserInterface::RegisterCommand(unsigned char parameterCount, const char *command, const char *commandHelp) void CommandParserInterface::RegisterCommand(unsigned char parameterCount, const char *command, const char *commandHelp)
{ {
RegisteredCommand rc; RegisteredCommand rc;
rc.command=command; rc.command=command;
rc.commandHelp=commandHelp; rc.commandHelp=commandHelp;
rc.parameterCount=parameterCount; rc.parameterCount=parameterCount;
commandList.Insert( command, rc, true, _FILE_AND_LINE_); commandList.Insert( command, rc, true, _FILE_AND_LINE_);
} }
bool CommandParserInterface::GetRegisteredCommand(const char *command, RegisteredCommand *rc) bool CommandParserInterface::GetRegisteredCommand(const char *command, RegisteredCommand *rc)
{ {
bool objectExists; bool objectExists;
unsigned index; unsigned index;
index=commandList.GetIndexFromKey(command, &objectExists); index=commandList.GetIndexFromKey(command, &objectExists);
if (objectExists) if (objectExists)
*rc=commandList[index]; *rc=commandList[index];
return objectExists; return objectExists;
} }
void CommandParserInterface::OnTransportChange(TransportInterface *transport) void CommandParserInterface::OnTransportChange(TransportInterface *transport)
{ {
(void) transport; (void) transport;
} }
void CommandParserInterface::OnNewIncomingConnection(const SystemAddress &systemAddress, TransportInterface *transport) void CommandParserInterface::OnNewIncomingConnection(const SystemAddress &systemAddress, TransportInterface *transport)
{ {
(void) systemAddress; (void) systemAddress;
(void) transport; (void) transport;
} }
void CommandParserInterface::OnConnectionLost(const SystemAddress &systemAddress, TransportInterface *transport) void CommandParserInterface::OnConnectionLost(const SystemAddress &systemAddress, TransportInterface *transport)
{ {
(void) systemAddress; (void) systemAddress;
(void) transport; (void) transport;
} }
void CommandParserInterface::ReturnResult(bool res, const char *command,TransportInterface *transport, const SystemAddress &systemAddress) void CommandParserInterface::ReturnResult(bool res, const char *command,TransportInterface *transport, const SystemAddress &systemAddress)
{ {
if (res) if (res)
transport->Send(systemAddress, "%s returned true.\r\n", command); transport->Send(systemAddress, "%s returned true.\r\n", command);
else else
transport->Send(systemAddress, "%s returned false.\r\n", command); transport->Send(systemAddress, "%s returned false.\r\n", command);
} }
void CommandParserInterface::ReturnResult(int res, const char *command,TransportInterface *transport, const SystemAddress &systemAddress) void CommandParserInterface::ReturnResult(int res, const char *command,TransportInterface *transport, const SystemAddress &systemAddress)
{ {
transport->Send(systemAddress, "%s returned %i.\r\n", command, res); transport->Send(systemAddress, "%s returned %i.\r\n", command, res);
} }
void CommandParserInterface::ReturnResult(const char *command, TransportInterface *transport, const SystemAddress &systemAddress) void CommandParserInterface::ReturnResult(const char *command, TransportInterface *transport, const SystemAddress &systemAddress)
{ {
transport->Send(systemAddress, "Successfully called %s.\r\n", command); transport->Send(systemAddress, "Successfully called %s.\r\n", command);
} }
void CommandParserInterface::ReturnResult(char *res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress) void CommandParserInterface::ReturnResult(char *res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress)
{ {
transport->Send(systemAddress, "%s returned %s.\r\n", command, res); transport->Send(systemAddress, "%s returned %s.\r\n", command, res);
} }
void CommandParserInterface::ReturnResult(SystemAddress res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress) void CommandParserInterface::ReturnResult(SystemAddress res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress)
{ {
char addr[128]; char addr[128];
systemAddress.ToString(false,addr); systemAddress.ToString(false,addr);
char addr2[128]; char addr2[128];
res.ToString(false,addr2); res.ToString(false,addr2);
transport->Send(systemAddress, "%s returned %s %s:%i\r\n", command,addr,addr2,res.GetPort()); transport->Send(systemAddress, "%s returned %s %s:%i\r\n", command,addr,addr2,res.GetPort());
} }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( pop ) #pragma warning( pop )
#endif #endif

View File

@@ -1,140 +1,140 @@
/// \file CommandParserInterface.h /// \file CommandParserInterface.h
/// \brief Contains CommandParserInterface , from which you derive custom command parsers /// \brief Contains CommandParserInterface , from which you derive custom command parsers
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __COMMAND_PARSER_INTERFACE #ifndef __COMMAND_PARSER_INTERFACE
#define __COMMAND_PARSER_INTERFACE #define __COMMAND_PARSER_INTERFACE
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "RakNetTypes.h" #include "RakNetTypes.h"
#include "DS_OrderedList.h" #include "DS_OrderedList.h"
#include "Export.h" #include "Export.h"
namespace RakNet namespace RakNet
{ {
/// Forward declarations /// Forward declarations
class TransportInterface; class TransportInterface;
/// \internal /// \internal
/// Contains the information related to one command registered with RegisterCommand() /// Contains the information related to one command registered with RegisterCommand()
/// Implemented so I can have an automatic help system via SendCommandList() /// Implemented so I can have an automatic help system via SendCommandList()
struct RAK_DLL_EXPORT RegisteredCommand struct RAK_DLL_EXPORT RegisteredCommand
{ {
const char *command; const char *command;
const char *commandHelp; const char *commandHelp;
unsigned char parameterCount; unsigned char parameterCount;
}; };
/// List of commands registered with RegisterCommand() /// List of commands registered with RegisterCommand()
int RAK_DLL_EXPORT RegisteredCommandComp( const char* const & key, const RegisteredCommand &data ); int RAK_DLL_EXPORT RegisteredCommandComp( const char* const & key, const RegisteredCommand &data );
/// \brief The interface used by command parsers. /// \brief The interface used by command parsers.
/// \details CommandParserInterface provides a set of functions and interfaces that plug into the ConsoleServer class. /// \details CommandParserInterface provides a set of functions and interfaces that plug into the ConsoleServer class.
/// Each CommandParserInterface works at the same time as other interfaces in the system. /// Each CommandParserInterface works at the same time as other interfaces in the system.
class RAK_DLL_EXPORT CommandParserInterface class RAK_DLL_EXPORT CommandParserInterface
{ {
public: public:
CommandParserInterface(); CommandParserInterface();
virtual ~CommandParserInterface(); virtual ~CommandParserInterface();
/// You are responsible for overriding this function and returning a static string, which will identifier your parser. /// You are responsible for overriding this function and returning a static string, which will identifier your parser.
/// This should return a static string /// This should return a static string
/// \return The name that you return. /// \return The name that you return.
virtual const char *GetName(void) const=0; virtual const char *GetName(void) const=0;
/// \brief A callback for when \a systemAddress has connected to us. /// \brief A callback for when \a systemAddress has connected to us.
/// \param[in] systemAddress The player that has connected. /// \param[in] systemAddress The player that has connected.
/// \param[in] transport The transport interface that sent us this information. Can be used to send messages to this or other players. /// \param[in] transport The transport interface that sent us this information. Can be used to send messages to this or other players.
virtual void OnNewIncomingConnection(const SystemAddress &systemAddress, TransportInterface *transport); virtual void OnNewIncomingConnection(const SystemAddress &systemAddress, TransportInterface *transport);
/// \brief A callback for when \a systemAddress has disconnected, either gracefully or forcefully /// \brief A callback for when \a systemAddress has disconnected, either gracefully or forcefully
/// \param[in] systemAddress The player that has disconnected. /// \param[in] systemAddress The player that has disconnected.
/// \param[in] transport The transport interface that sent us this information. /// \param[in] transport The transport interface that sent us this information.
virtual void OnConnectionLost(const SystemAddress &systemAddress, TransportInterface *transport); virtual void OnConnectionLost(const SystemAddress &systemAddress, TransportInterface *transport);
/// \brief A callback for when you are expected to send a brief description of your parser to \a systemAddress /// \brief A callback for when you are expected to send a brief description of your parser to \a systemAddress
/// \param[in] transport The transport interface we can use to write to /// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that requested help. /// \param[in] systemAddress The player that requested help.
virtual void SendHelp(TransportInterface *transport, const SystemAddress &systemAddress)=0; virtual void SendHelp(TransportInterface *transport, const SystemAddress &systemAddress)=0;
/// \brief Given \a command with parameters \a parameterList , do whatever processing you wish. /// \brief Given \a command with parameters \a parameterList , do whatever processing you wish.
/// \param[in] command The command to process /// \param[in] command The command to process
/// \param[in] numParameters How many parameters were passed along with the command /// \param[in] numParameters How many parameters were passed along with the command
/// \param[in] parameterList The list of parameters. parameterList[0] is the first parameter and so on. /// \param[in] parameterList The list of parameters. parameterList[0] is the first parameter and so on.
/// \param[in] transport The transport interface we can use to write to /// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player that sent this command. /// \param[in] systemAddress The player that sent this command.
/// \param[in] originalString The string that was actually sent over the network, in case you want to do your own parsing /// \param[in] originalString The string that was actually sent over the network, in case you want to do your own parsing
virtual bool OnCommand(const char *command, unsigned numParameters, char **parameterList, TransportInterface *transport, const SystemAddress &systemAddress, const char *originalString)=0; virtual bool OnCommand(const char *command, unsigned numParameters, char **parameterList, TransportInterface *transport, const SystemAddress &systemAddress, const char *originalString)=0;
/// \brief This is called every time transport interface is registered. /// \brief This is called every time transport interface is registered.
/// \details If you want to save a copy of the TransportInterface pointer /// \details If you want to save a copy of the TransportInterface pointer
/// This is the place to do it /// This is the place to do it
/// \param[in] transport The new TransportInterface /// \param[in] transport The new TransportInterface
virtual void OnTransportChange(TransportInterface *transport); virtual void OnTransportChange(TransportInterface *transport);
/// \internal /// \internal
/// Scan commandList and return the associated array /// Scan commandList and return the associated array
/// \param[in] command The string to find /// \param[in] command The string to find
/// \param[out] rc Contains the result of this operation /// \param[out] rc Contains the result of this operation
/// \return True if we found the command, false otherwise /// \return True if we found the command, false otherwise
virtual bool GetRegisteredCommand(const char *command, RegisteredCommand *rc); virtual bool GetRegisteredCommand(const char *command, RegisteredCommand *rc);
/// \internal /// \internal
/// Goes through str, replacing the delineating character with 0's. /// Goes through str, replacing the delineating character with 0's.
/// \param[in] str The string sent by the transport interface /// \param[in] str The string sent by the transport interface
/// \param[in] delineator The character to scan for to use as a delineator /// \param[in] delineator The character to scan for to use as a delineator
/// \param[in] delineatorToggle When encountered the delineator replacement is toggled on and off /// \param[in] delineatorToggle When encountered the delineator replacement is toggled on and off
/// \param[out] numParameters How many pointers were written to \a parameterList /// \param[out] numParameters How many pointers were written to \a parameterList
/// \param[out] parameterList An array of pointers to characters. Will hold pointers to locations inside \a str /// \param[out] parameterList An array of pointers to characters. Will hold pointers to locations inside \a str
/// \param[in] parameterListLength How big the \a parameterList array is /// \param[in] parameterListLength How big the \a parameterList array is
static void ParseConsoleString(char *str, const char delineator, unsigned char delineatorToggle, unsigned *numParameters, char **parameterList, unsigned parameterListLength); static void ParseConsoleString(char *str, const char delineator, unsigned char delineatorToggle, unsigned *numParameters, char **parameterList, unsigned parameterListLength);
/// \internal /// \internal
/// Goes through the variable commandList and sends the command portion of each struct /// Goes through the variable commandList and sends the command portion of each struct
/// \param[in] transport The transport interface we can use to write to /// \param[in] transport The transport interface we can use to write to
/// \param[in] systemAddress The player to write to /// \param[in] systemAddress The player to write to
virtual void SendCommandList(TransportInterface *transport, const SystemAddress &systemAddress); virtual void SendCommandList(TransportInterface *transport, const SystemAddress &systemAddress);
static const unsigned char VARIABLE_NUMBER_OF_PARAMETERS; static const unsigned char VARIABLE_NUMBER_OF_PARAMETERS;
// Currently only takes static strings - doesn't make a copy of what you pass. // Currently only takes static strings - doesn't make a copy of what you pass.
// parameterCount is the number of parameters that the sender has to include with the command. // parameterCount is the number of parameters that the sender has to include with the command.
// Pass 255 to parameterCount to indicate variable number of parameters // Pass 255 to parameterCount to indicate variable number of parameters
/// Registers a command. /// Registers a command.
/// \param[in] parameterCount How many parameters your command requires. If you want to accept a variable number of commands, pass CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS /// \param[in] parameterCount How many parameters your command requires. If you want to accept a variable number of commands, pass CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS
/// \param[in] command A pointer to a STATIC string that has your command. I keep a copy of the pointer here so don't deallocate the string. /// \param[in] command A pointer to a STATIC string that has your command. I keep a copy of the pointer here so don't deallocate the string.
/// \param[in] commandHelp A pointer to a STATIC string that has the help information for your command. I keep a copy of the pointer here so don't deallocate the string. /// \param[in] commandHelp A pointer to a STATIC string that has the help information for your command. I keep a copy of the pointer here so don't deallocate the string.
virtual void RegisterCommand(unsigned char parameterCount, const char *command, const char *commandHelp); virtual void RegisterCommand(unsigned char parameterCount, const char *command, const char *commandHelp);
/// \brief Just writes a string to the remote system based on the result ( \a res ) of your operation /// \brief Just writes a string to the remote system based on the result ( \a res ) of your operation
/// \details This is not necessary to call, but makes it easier to return results of function calls. /// \details This is not necessary to call, but makes it easier to return results of function calls.
/// \param[in] res The result to write /// \param[in] res The result to write
/// \param[in] command The command that this result came from /// \param[in] command The command that this result came from
/// \param[in] transport The transport interface that will be written to /// \param[in] transport The transport interface that will be written to
/// \param[in] systemAddress The player this result will be sent to /// \param[in] systemAddress The player this result will be sent to
virtual void ReturnResult(bool res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress); virtual void ReturnResult(bool res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress);
virtual void ReturnResult(char *res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress); virtual void ReturnResult(char *res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress);
virtual void ReturnResult(SystemAddress res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress); virtual void ReturnResult(SystemAddress res, const char *command, TransportInterface *transport, const SystemAddress &systemAddress);
virtual void ReturnResult(int res, const char *command,TransportInterface *transport, const SystemAddress &systemAddress); virtual void ReturnResult(int res, const char *command,TransportInterface *transport, const SystemAddress &systemAddress);
/// \brief Just writes a string to the remote system when you are calling a function that has no return value. /// \brief Just writes a string to the remote system when you are calling a function that has no return value.
/// \details This is not necessary to call, but makes it easier to return results of function calls. /// \details This is not necessary to call, but makes it easier to return results of function calls.
/// \param[in] res The result to write /// \param[in] res The result to write
/// \param[in] command The command that this result came from /// \param[in] command The command that this result came from
/// \param[in] transport The transport interface that will be written to /// \param[in] transport The transport interface that will be written to
/// \param[in] systemAddress The player this result will be sent to /// \param[in] systemAddress The player this result will be sent to
virtual void ReturnResult(const char *command,TransportInterface *transport, const SystemAddress &systemAddress); virtual void ReturnResult(const char *command,TransportInterface *transport, const SystemAddress &systemAddress);
protected: protected:
DataStructures::OrderedList<const char*, RegisteredCommand, RegisteredCommandComp> commandList; DataStructures::OrderedList<const char*, RegisteredCommand, RegisteredCommandComp> commandList;
}; };
} // namespace RakNet } // namespace RakNet
#endif #endif

View File

@@ -1,299 +1,299 @@
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_ConnectionGraph2==1 #if _RAKNET_SUPPORT_ConnectionGraph2==1
#include "ConnectionGraph2.h" #include "ConnectionGraph2.h"
#include "RakPeerInterface.h" #include "RakPeerInterface.h"
#include "MessageIdentifiers.h" #include "MessageIdentifiers.h"
#include "BitStream.h" #include "BitStream.h"
using namespace RakNet; using namespace RakNet;
STATIC_FACTORY_DEFINITIONS(ConnectionGraph2,ConnectionGraph2); STATIC_FACTORY_DEFINITIONS(ConnectionGraph2,ConnectionGraph2);
int RakNet::ConnectionGraph2::RemoteSystemComp( const RakNetGUID &key, RemoteSystem * const &data ) int RakNet::ConnectionGraph2::RemoteSystemComp( const RakNetGUID &key, RemoteSystem * const &data )
{ {
if (key < data->guid) if (key < data->guid)
return -1; return -1;
if (key > data->guid) if (key > data->guid)
return 1; return 1;
return 0; return 0;
} }
int RakNet::ConnectionGraph2::SystemAddressAndGuidComp( const SystemAddressAndGuid &key, const SystemAddressAndGuid &data ) int RakNet::ConnectionGraph2::SystemAddressAndGuidComp( const SystemAddressAndGuid &key, const SystemAddressAndGuid &data )
{ {
if (key.guid<data.guid) if (key.guid<data.guid)
return -1; return -1;
if (key.guid>data.guid) if (key.guid>data.guid)
return 1; return 1;
return 0; return 0;
} }
ConnectionGraph2::ConnectionGraph2() ConnectionGraph2::ConnectionGraph2()
{ {
autoProcessNewConnections=true; autoProcessNewConnections=true;
} }
ConnectionGraph2::~ConnectionGraph2() ConnectionGraph2::~ConnectionGraph2()
{ {
} }
bool ConnectionGraph2::GetConnectionListForRemoteSystem(RakNetGUID remoteSystemGuid, SystemAddress *saOut, RakNetGUID *guidOut, unsigned int *outLength) bool ConnectionGraph2::GetConnectionListForRemoteSystem(RakNetGUID remoteSystemGuid, SystemAddress *saOut, RakNetGUID *guidOut, unsigned int *outLength)
{ {
if ((saOut==0 && guidOut==0) || outLength==0 || *outLength==0 || remoteSystemGuid==UNASSIGNED_RAKNET_GUID) if ((saOut==0 && guidOut==0) || outLength==0 || *outLength==0 || remoteSystemGuid==UNASSIGNED_RAKNET_GUID)
{ {
*outLength=0; *outLength=0;
return false; return false;
} }
bool objectExists; bool objectExists;
unsigned int idx = remoteSystems.GetIndexFromKey(remoteSystemGuid, &objectExists); unsigned int idx = remoteSystems.GetIndexFromKey(remoteSystemGuid, &objectExists);
if (objectExists==false) if (objectExists==false)
{ {
*outLength=0; *outLength=0;
return false; return false;
} }
unsigned int idx2; unsigned int idx2;
if (remoteSystems[idx]->remoteConnections.Size() < *outLength) if (remoteSystems[idx]->remoteConnections.Size() < *outLength)
*outLength=remoteSystems[idx]->remoteConnections.Size(); *outLength=remoteSystems[idx]->remoteConnections.Size();
for (idx2=0; idx2 < *outLength; idx2++) for (idx2=0; idx2 < *outLength; idx2++)
{ {
if (guidOut) if (guidOut)
guidOut[idx2]=remoteSystems[idx]->remoteConnections[idx2].guid; guidOut[idx2]=remoteSystems[idx]->remoteConnections[idx2].guid;
if (saOut) if (saOut)
saOut[idx2]=remoteSystems[idx]->remoteConnections[idx2].systemAddress; saOut[idx2]=remoteSystems[idx]->remoteConnections[idx2].systemAddress;
} }
return true; return true;
} }
bool ConnectionGraph2::ConnectionExists(RakNetGUID g1, RakNetGUID g2) bool ConnectionGraph2::ConnectionExists(RakNetGUID g1, RakNetGUID g2)
{ {
if (g1==g2) if (g1==g2)
return false; return false;
bool objectExists; bool objectExists;
unsigned int idx = remoteSystems.GetIndexFromKey(g1, &objectExists); unsigned int idx = remoteSystems.GetIndexFromKey(g1, &objectExists);
if (objectExists==false) if (objectExists==false)
{ {
return false; return false;
} }
SystemAddressAndGuid sag; SystemAddressAndGuid sag;
sag.guid=g2; sag.guid=g2;
return remoteSystems[idx]->remoteConnections.HasData(sag); return remoteSystems[idx]->remoteConnections.HasData(sag);
} }
uint16_t ConnectionGraph2::GetPingBetweenSystems(RakNetGUID g1, RakNetGUID g2) const uint16_t ConnectionGraph2::GetPingBetweenSystems(RakNetGUID g1, RakNetGUID g2) const
{ {
if (g1==g2) if (g1==g2)
return 0; return 0;
if (g1==rakPeerInterface->GetMyGUID()) if (g1==rakPeerInterface->GetMyGUID())
return (uint16_t) rakPeerInterface->GetAveragePing(g2); return (uint16_t) rakPeerInterface->GetAveragePing(g2);
if (g2==rakPeerInterface->GetMyGUID()) if (g2==rakPeerInterface->GetMyGUID())
return (uint16_t) rakPeerInterface->GetAveragePing(g1); return (uint16_t) rakPeerInterface->GetAveragePing(g1);
bool objectExists; bool objectExists;
unsigned int idx = remoteSystems.GetIndexFromKey(g1, &objectExists); unsigned int idx = remoteSystems.GetIndexFromKey(g1, &objectExists);
if (objectExists==false) if (objectExists==false)
{ {
return (uint16_t) -1; return (uint16_t) -1;
} }
SystemAddressAndGuid sag; SystemAddressAndGuid sag;
sag.guid=g2; sag.guid=g2;
unsigned int idx2 = remoteSystems[idx]->remoteConnections.GetIndexFromKey(sag, &objectExists); unsigned int idx2 = remoteSystems[idx]->remoteConnections.GetIndexFromKey(sag, &objectExists);
if (objectExists==false) if (objectExists==false)
{ {
return (uint16_t) -1; return (uint16_t) -1;
} }
return remoteSystems[idx]->remoteConnections[idx2].sendersPingToThatSystem; return remoteSystems[idx]->remoteConnections[idx2].sendersPingToThatSystem;
} }
/// Returns the system with the lowest total ping among all its connections. This can be used as the 'best host' for a peer to peer session /// Returns the system with the lowest total ping among all its connections. This can be used as the 'best host' for a peer to peer session
RakNetGUID ConnectionGraph2::GetLowestAveragePingSystem(void) const RakNetGUID ConnectionGraph2::GetLowestAveragePingSystem(void) const
{ {
float lowestPing=-1.0; float lowestPing=-1.0;
unsigned int lowestPingIdx=(unsigned int) -1; unsigned int lowestPingIdx=(unsigned int) -1;
float thisAvePing=0.0f; float thisAvePing=0.0f;
unsigned int idx, idx2; unsigned int idx, idx2;
int ap, count=0; int ap, count=0;
for (idx=0; idx<remoteSystems.Size(); idx++) for (idx=0; idx<remoteSystems.Size(); idx++)
{ {
thisAvePing=0.0f; thisAvePing=0.0f;
ap = rakPeerInterface->GetAveragePing(remoteSystems[idx]->guid); ap = rakPeerInterface->GetAveragePing(remoteSystems[idx]->guid);
if (ap!=-1) if (ap!=-1)
{ {
thisAvePing+=(float) ap; thisAvePing+=(float) ap;
count++; count++;
} }
} }
if (count>0) if (count>0)
{ {
lowestPing=thisAvePing/count; lowestPing=thisAvePing/count;
} }
for (idx=0; idx<remoteSystems.Size(); idx++) for (idx=0; idx<remoteSystems.Size(); idx++)
{ {
thisAvePing=0.0f; thisAvePing=0.0f;
count=0; count=0;
RemoteSystem *remoteSystem = remoteSystems[idx]; RemoteSystem *remoteSystem = remoteSystems[idx];
for (idx2=0; idx2 < remoteSystem->remoteConnections.Size(); idx2++) for (idx2=0; idx2 < remoteSystem->remoteConnections.Size(); idx2++)
{ {
ap=remoteSystem->remoteConnections[idx2].sendersPingToThatSystem; ap=remoteSystem->remoteConnections[idx2].sendersPingToThatSystem;
if (ap!=-1) if (ap!=-1)
{ {
thisAvePing+=(float) ap; thisAvePing+=(float) ap;
count++; count++;
} }
} }
if (count>0 && (lowestPing==-1.0f || thisAvePing/count < lowestPing)) if (count>0 && (lowestPing==-1.0f || thisAvePing/count < lowestPing))
{ {
lowestPing=thisAvePing/count; lowestPing=thisAvePing/count;
lowestPingIdx=idx; lowestPingIdx=idx;
} }
} }
if (lowestPingIdx==(unsigned int) -1) if (lowestPingIdx==(unsigned int) -1)
return rakPeerInterface->GetMyGUID(); return rakPeerInterface->GetMyGUID();
return remoteSystems[lowestPingIdx]->guid; return remoteSystems[lowestPingIdx]->guid;
} }
void ConnectionGraph2::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason ) void ConnectionGraph2::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
{ {
// Send notice to all existing connections // Send notice to all existing connections
RakNet::BitStream bs; RakNet::BitStream bs;
if (lostConnectionReason==LCR_CONNECTION_LOST) if (lostConnectionReason==LCR_CONNECTION_LOST)
bs.Write((MessageID)ID_REMOTE_CONNECTION_LOST); bs.Write((MessageID)ID_REMOTE_CONNECTION_LOST);
else else
bs.Write((MessageID)ID_REMOTE_DISCONNECTION_NOTIFICATION); bs.Write((MessageID)ID_REMOTE_DISCONNECTION_NOTIFICATION);
bs.Write(systemAddress); bs.Write(systemAddress);
bs.Write(rakNetGUID); bs.Write(rakNetGUID);
SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,true); SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,true);
bool objectExists; bool objectExists;
unsigned int idx = remoteSystems.GetIndexFromKey(rakNetGUID, &objectExists); unsigned int idx = remoteSystems.GetIndexFromKey(rakNetGUID, &objectExists);
if (objectExists) if (objectExists)
{ {
RakNet::OP_DELETE(remoteSystems[idx],_FILE_AND_LINE_); RakNet::OP_DELETE(remoteSystems[idx],_FILE_AND_LINE_);
remoteSystems.RemoveAtIndex(idx); remoteSystems.RemoveAtIndex(idx);
} }
} }
void ConnectionGraph2::SetAutoProcessNewConnections(bool b) void ConnectionGraph2::SetAutoProcessNewConnections(bool b)
{ {
autoProcessNewConnections=b; autoProcessNewConnections=b;
} }
bool ConnectionGraph2::GetAutoProcessNewConnections(void) const bool ConnectionGraph2::GetAutoProcessNewConnections(void) const
{ {
return autoProcessNewConnections; return autoProcessNewConnections;
} }
void ConnectionGraph2::AddParticipant(const SystemAddress &systemAddress, RakNetGUID rakNetGUID) void ConnectionGraph2::AddParticipant(const SystemAddress &systemAddress, RakNetGUID rakNetGUID)
{ {
// Relay the new connection to other systems. // Relay the new connection to other systems.
RakNet::BitStream bs; RakNet::BitStream bs;
bs.Write((MessageID)ID_REMOTE_NEW_INCOMING_CONNECTION); bs.Write((MessageID)ID_REMOTE_NEW_INCOMING_CONNECTION);
bs.Write((uint32_t)1); bs.Write((uint32_t)1);
bs.Write(systemAddress); bs.Write(systemAddress);
bs.Write(rakNetGUID); bs.Write(rakNetGUID);
bs.WriteCasted<uint16_t>(rakPeerInterface->GetAveragePing(rakNetGUID)); bs.WriteCasted<uint16_t>(rakPeerInterface->GetAveragePing(rakNetGUID));
SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,true); SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,true);
// Send everyone to the new guy // Send everyone to the new guy
DataStructures::List<SystemAddress> addresses; DataStructures::List<SystemAddress> addresses;
DataStructures::List<RakNetGUID> guids; DataStructures::List<RakNetGUID> guids;
rakPeerInterface->GetSystemList(addresses, guids); rakPeerInterface->GetSystemList(addresses, guids);
bs.Reset(); bs.Reset();
bs.Write((MessageID)ID_REMOTE_NEW_INCOMING_CONNECTION); bs.Write((MessageID)ID_REMOTE_NEW_INCOMING_CONNECTION);
BitSize_t writeOffset = bs.GetWriteOffset(); BitSize_t writeOffset = bs.GetWriteOffset();
bs.Write((uint32_t) addresses.Size()); bs.Write((uint32_t) addresses.Size());
unsigned int i; unsigned int i;
uint32_t count=0; uint32_t count=0;
for (i=0; i < addresses.Size(); i++) for (i=0; i < addresses.Size(); i++)
{ {
if (addresses[i]==systemAddress) if (addresses[i]==systemAddress)
continue; continue;
bs.Write(addresses[i]); bs.Write(addresses[i]);
bs.Write(guids[i]); bs.Write(guids[i]);
bs.WriteCasted<uint16_t>(rakPeerInterface->GetAveragePing(guids[i])); bs.WriteCasted<uint16_t>(rakPeerInterface->GetAveragePing(guids[i]));
count++; count++;
} }
if (count>0) if (count>0)
{ {
BitSize_t writeOffset2 = bs.GetWriteOffset(); BitSize_t writeOffset2 = bs.GetWriteOffset();
bs.SetWriteOffset(writeOffset); bs.SetWriteOffset(writeOffset);
bs.Write(count); bs.Write(count);
bs.SetWriteOffset(writeOffset2); bs.SetWriteOffset(writeOffset2);
SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,false); SendUnified(&bs,HIGH_PRIORITY,RELIABLE_ORDERED,0,systemAddress,false);
} }
bool objectExists; bool objectExists;
unsigned int ii = remoteSystems.GetIndexFromKey(rakNetGUID, &objectExists); unsigned int ii = remoteSystems.GetIndexFromKey(rakNetGUID, &objectExists);
if (objectExists==false) if (objectExists==false)
{ {
RemoteSystem* remoteSystem = RakNet::OP_NEW<RemoteSystem>(_FILE_AND_LINE_); RemoteSystem* remoteSystem = RakNet::OP_NEW<RemoteSystem>(_FILE_AND_LINE_);
remoteSystem->guid=rakNetGUID; remoteSystem->guid=rakNetGUID;
remoteSystems.InsertAtIndex(remoteSystem,ii,_FILE_AND_LINE_); remoteSystems.InsertAtIndex(remoteSystem,ii,_FILE_AND_LINE_);
} }
} }
void ConnectionGraph2::GetParticipantList(DataStructures::OrderedList<RakNetGUID, RakNetGUID> &participantList) void ConnectionGraph2::GetParticipantList(DataStructures::OrderedList<RakNetGUID, RakNetGUID> &participantList)
{ {
participantList.Clear(true, _FILE_AND_LINE_); participantList.Clear(true, _FILE_AND_LINE_);
unsigned int i; unsigned int i;
for (i=0; i < remoteSystems.Size(); i++) for (i=0; i < remoteSystems.Size(); i++)
participantList.InsertAtEnd(remoteSystems[i]->guid, _FILE_AND_LINE_); participantList.InsertAtEnd(remoteSystems[i]->guid, _FILE_AND_LINE_);
} }
void ConnectionGraph2::OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming) void ConnectionGraph2::OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
{ {
(void) isIncoming; (void) isIncoming;
if (autoProcessNewConnections) if (autoProcessNewConnections)
AddParticipant(systemAddress, rakNetGUID); AddParticipant(systemAddress, rakNetGUID);
} }
PluginReceiveResult ConnectionGraph2::OnReceive(Packet *packet) PluginReceiveResult ConnectionGraph2::OnReceive(Packet *packet)
{ {
if (packet->data[0]==ID_REMOTE_CONNECTION_LOST || packet->data[0]==ID_REMOTE_DISCONNECTION_NOTIFICATION) if (packet->data[0]==ID_REMOTE_CONNECTION_LOST || packet->data[0]==ID_REMOTE_DISCONNECTION_NOTIFICATION)
{ {
bool objectExists; bool objectExists;
unsigned idx = remoteSystems.GetIndexFromKey(packet->guid, &objectExists); unsigned idx = remoteSystems.GetIndexFromKey(packet->guid, &objectExists);
if (objectExists) if (objectExists)
{ {
RakNet::BitStream bs(packet->data,packet->length,false); RakNet::BitStream bs(packet->data,packet->length,false);
bs.IgnoreBytes(1); bs.IgnoreBytes(1);
SystemAddressAndGuid saag; SystemAddressAndGuid saag;
bs.Read(saag.systemAddress); bs.Read(saag.systemAddress);
bs.Read(saag.guid); bs.Read(saag.guid);
unsigned long idx2 = remoteSystems[idx]->remoteConnections.GetIndexFromKey(saag, &objectExists); unsigned long idx2 = remoteSystems[idx]->remoteConnections.GetIndexFromKey(saag, &objectExists);
if (objectExists) if (objectExists)
remoteSystems[idx]->remoteConnections.RemoveAtIndex(idx2); remoteSystems[idx]->remoteConnections.RemoveAtIndex(idx2);
} }
} }
else if (packet->data[0]==ID_REMOTE_NEW_INCOMING_CONNECTION) else if (packet->data[0]==ID_REMOTE_NEW_INCOMING_CONNECTION)
{ {
bool objectExists; bool objectExists;
unsigned idx = remoteSystems.GetIndexFromKey(packet->guid, &objectExists); unsigned idx = remoteSystems.GetIndexFromKey(packet->guid, &objectExists);
if (objectExists) if (objectExists)
{ {
uint32_t numAddresses; uint32_t numAddresses;
RakNet::BitStream bs(packet->data,packet->length,false); RakNet::BitStream bs(packet->data,packet->length,false);
bs.IgnoreBytes(1); bs.IgnoreBytes(1);
bs.Read(numAddresses); bs.Read(numAddresses);
for (unsigned int idx2=0; idx2 < numAddresses; idx2++) for (unsigned int idx2=0; idx2 < numAddresses; idx2++)
{ {
SystemAddressAndGuid saag; SystemAddressAndGuid saag;
bs.Read(saag.systemAddress); bs.Read(saag.systemAddress);
bs.Read(saag.guid); bs.Read(saag.guid);
bs.Read(saag.sendersPingToThatSystem); bs.Read(saag.sendersPingToThatSystem);
bool objectExists; bool objectExists;
unsigned int ii = remoteSystems[idx]->remoteConnections.GetIndexFromKey(saag, &objectExists); unsigned int ii = remoteSystems[idx]->remoteConnections.GetIndexFromKey(saag, &objectExists);
if (objectExists==false) if (objectExists==false)
remoteSystems[idx]->remoteConnections.InsertAtIndex(saag,ii,_FILE_AND_LINE_); remoteSystems[idx]->remoteConnections.InsertAtIndex(saag,ii,_FILE_AND_LINE_);
} }
} }
} }
return RR_CONTINUE_PROCESSING; return RR_CONTINUE_PROCESSING;
} }
#endif // _RAKNET_SUPPORT_* #endif // _RAKNET_SUPPORT_*

View File

@@ -1,118 +1,118 @@
/// \file ConnectionGraph2.h /// \file ConnectionGraph2.h
/// \brief Connection graph plugin, version 2. Tells new systems about existing and new connections /// \brief Connection graph plugin, version 2. Tells new systems about existing and new connections
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_ConnectionGraph2==1 #if _RAKNET_SUPPORT_ConnectionGraph2==1
#ifndef __CONNECTION_GRAPH_2_H #ifndef __CONNECTION_GRAPH_2_H
#define __CONNECTION_GRAPH_2_H #define __CONNECTION_GRAPH_2_H
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "RakNetTypes.h" #include "RakNetTypes.h"
#include "PluginInterface2.h" #include "PluginInterface2.h"
#include "DS_List.h" #include "DS_List.h"
#include "DS_WeightedGraph.h" #include "DS_WeightedGraph.h"
#include "GetTime.h" #include "GetTime.h"
#include "Export.h" #include "Export.h"
namespace RakNet namespace RakNet
{ {
/// Forward declarations /// Forward declarations
class RakPeerInterface; class RakPeerInterface;
/// \brief A one hop connection graph. /// \brief A one hop connection graph.
/// \details Sends ID_REMOTE_CONNECTION_LOST, ID_REMOTE_DISCONNECTION_NOTIFICATION, ID_REMOTE_NEW_INCOMING_CONNECTION<BR> /// \details Sends ID_REMOTE_CONNECTION_LOST, ID_REMOTE_DISCONNECTION_NOTIFICATION, ID_REMOTE_NEW_INCOMING_CONNECTION<BR>
/// All identifiers are followed by SystemAddress, then RakNetGUID /// All identifiers are followed by SystemAddress, then RakNetGUID
/// Also stores the list for you, which you can access with GetConnectionListForRemoteSystem /// Also stores the list for you, which you can access with GetConnectionListForRemoteSystem
/// \ingroup CONNECTION_GRAPH_GROUP /// \ingroup CONNECTION_GRAPH_GROUP
class RAK_DLL_EXPORT ConnectionGraph2 : public PluginInterface2 class RAK_DLL_EXPORT ConnectionGraph2 : public PluginInterface2
{ {
public: public:
// GetInstance() and DestroyInstance(instance*) // GetInstance() and DestroyInstance(instance*)
STATIC_FACTORY_DECLARATIONS(ConnectionGraph2) STATIC_FACTORY_DECLARATIONS(ConnectionGraph2)
ConnectionGraph2(); ConnectionGraph2();
~ConnectionGraph2(); ~ConnectionGraph2();
/// \brief Given a remote system identified by RakNetGUID, return the list of SystemAddresses and RakNetGUIDs they are connected to /// \brief Given a remote system identified by RakNetGUID, return the list of SystemAddresses and RakNetGUIDs they are connected to
/// \param[in] remoteSystemGuid Which system we are referring to. This only works for remote systems, not ourselves. /// \param[in] remoteSystemGuid Which system we are referring to. This only works for remote systems, not ourselves.
/// \param[out] saOut A preallocated array to hold the output list of SystemAddress. Can be 0 if you don't care. /// \param[out] saOut A preallocated array to hold the output list of SystemAddress. Can be 0 if you don't care.
/// \param[out] guidOut A preallocated array to hold the output list of RakNetGUID. Can be 0 if you don't care. /// \param[out] guidOut A preallocated array to hold the output list of RakNetGUID. Can be 0 if you don't care.
/// \param[in,out] outLength On input, the size of \a saOut and \a guidOut. On output, modified to reflect the number of elements actually written /// \param[in,out] outLength On input, the size of \a saOut and \a guidOut. On output, modified to reflect the number of elements actually written
/// \return True if \a remoteSystemGuid was found. Otherwise false, and \a saOut, \a guidOut remain unchanged. \a outLength will be set to 0. /// \return True if \a remoteSystemGuid was found. Otherwise false, and \a saOut, \a guidOut remain unchanged. \a outLength will be set to 0.
bool GetConnectionListForRemoteSystem(RakNetGUID remoteSystemGuid, SystemAddress *saOut, RakNetGUID *guidOut, unsigned int *outLength); bool GetConnectionListForRemoteSystem(RakNetGUID remoteSystemGuid, SystemAddress *saOut, RakNetGUID *guidOut, unsigned int *outLength);
/// Returns if g1 is connected to g2 /// Returns if g1 is connected to g2
bool ConnectionExists(RakNetGUID g1, RakNetGUID g2); bool ConnectionExists(RakNetGUID g1, RakNetGUID g2);
/// Returns the average ping between two systems in the connection graph. Returns -1 if no connection exists between those systems /// Returns the average ping between two systems in the connection graph. Returns -1 if no connection exists between those systems
uint16_t GetPingBetweenSystems(RakNetGUID g1, RakNetGUID g2) const; uint16_t GetPingBetweenSystems(RakNetGUID g1, RakNetGUID g2) const;
/// Returns the system with the lowest average ping among all its connections. /// Returns the system with the lowest average ping among all its connections.
/// If you need one system in the peer to peer group to relay data, have the FullyConnectedMesh2 host call this function after host migration, and use that system /// If you need one system in the peer to peer group to relay data, have the FullyConnectedMesh2 host call this function after host migration, and use that system
RakNetGUID GetLowestAveragePingSystem(void) const; RakNetGUID GetLowestAveragePingSystem(void) const;
/// \brief If called with false, then new connections are only added to the connection graph when you call ProcessNewConnection(); /// \brief If called with false, then new connections are only added to the connection graph when you call ProcessNewConnection();
/// \details This is useful if you want to perform validation before connecting a system to a mesh, or if you want a submesh (for example a server cloud) /// \details This is useful if you want to perform validation before connecting a system to a mesh, or if you want a submesh (for example a server cloud)
/// \param[in] b True to automatically call ProcessNewConnection() on any new connection, false to not do so. Defaults to true. /// \param[in] b True to automatically call ProcessNewConnection() on any new connection, false to not do so. Defaults to true.
void SetAutoProcessNewConnections(bool b); void SetAutoProcessNewConnections(bool b);
/// \brief Returns value passed to SetAutoProcessNewConnections() /// \brief Returns value passed to SetAutoProcessNewConnections()
/// \return Value passed to SetAutoProcessNewConnections(), or the default of true if it was never called /// \return Value passed to SetAutoProcessNewConnections(), or the default of true if it was never called
bool GetAutoProcessNewConnections(void) const; bool GetAutoProcessNewConnections(void) const;
/// \brief If you call SetAutoProcessNewConnections(false);, then you will need to manually call ProcessNewConnection() on new connections /// \brief If you call SetAutoProcessNewConnections(false);, then you will need to manually call ProcessNewConnection() on new connections
/// \details On ID_NEW_INCOMING_CONNECTION or ID_CONNECTION_REQUEST_ACCEPTED, adds that system to the graph /// \details On ID_NEW_INCOMING_CONNECTION or ID_CONNECTION_REQUEST_ACCEPTED, adds that system to the graph
/// Do not call ProcessNewConnection() manually otherwise /// Do not call ProcessNewConnection() manually otherwise
/// \param[in] The packet->SystemAddress member /// \param[in] The packet->SystemAddress member
/// \param[in] The packet->guid member /// \param[in] The packet->guid member
void AddParticipant(const SystemAddress &systemAddress, RakNetGUID rakNetGUID); void AddParticipant(const SystemAddress &systemAddress, RakNetGUID rakNetGUID);
/// Get the participants added with AddParticipant() /// Get the participants added with AddParticipant()
/// \param[out] participantList Participants added with AddParticipant(); /// \param[out] participantList Participants added with AddParticipant();
void GetParticipantList(DataStructures::OrderedList<RakNetGUID, RakNetGUID> &participantList); void GetParticipantList(DataStructures::OrderedList<RakNetGUID, RakNetGUID> &participantList);
/// \internal /// \internal
struct SystemAddressAndGuid struct SystemAddressAndGuid
{ {
SystemAddress systemAddress; SystemAddress systemAddress;
RakNetGUID guid; RakNetGUID guid;
uint16_t sendersPingToThatSystem; uint16_t sendersPingToThatSystem;
}; };
/// \internal /// \internal
static int SystemAddressAndGuidComp( const SystemAddressAndGuid &key, const SystemAddressAndGuid &data ); static int SystemAddressAndGuidComp( const SystemAddressAndGuid &key, const SystemAddressAndGuid &data );
/// \internal /// \internal
struct RemoteSystem struct RemoteSystem
{ {
DataStructures::OrderedList<SystemAddressAndGuid,SystemAddressAndGuid,ConnectionGraph2::SystemAddressAndGuidComp> remoteConnections; DataStructures::OrderedList<SystemAddressAndGuid,SystemAddressAndGuid,ConnectionGraph2::SystemAddressAndGuidComp> remoteConnections;
RakNetGUID guid; RakNetGUID guid;
}; };
/// \internal /// \internal
static int RemoteSystemComp( const RakNetGUID &key, RemoteSystem * const &data ); static int RemoteSystemComp( const RakNetGUID &key, RemoteSystem * const &data );
protected: protected:
/// \internal /// \internal
virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason ); virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
/// \internal /// \internal
virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming); virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming);
/// \internal /// \internal
virtual PluginReceiveResult OnReceive(Packet *packet); virtual PluginReceiveResult OnReceive(Packet *packet);
// List of systems I am connected to, which in turn stores which systems they are connected to // List of systems I am connected to, which in turn stores which systems they are connected to
DataStructures::OrderedList<RakNetGUID, RemoteSystem*, ConnectionGraph2::RemoteSystemComp> remoteSystems; DataStructures::OrderedList<RakNetGUID, RemoteSystem*, ConnectionGraph2::RemoteSystemComp> remoteSystems;
bool autoProcessNewConnections; bool autoProcessNewConnections;
}; };
} // namespace RakNet } // namespace RakNet
#endif // #ifndef __CONNECTION_GRAPH_2_H #endif // #ifndef __CONNECTION_GRAPH_2_H
#endif // _RAKNET_SUPPORT_* #endif // _RAKNET_SUPPORT_*

View File

@@ -1,311 +1,311 @@
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_ConsoleServer==1 #if _RAKNET_SUPPORT_ConsoleServer==1
#include "ConsoleServer.h" #include "ConsoleServer.h"
#include "TransportInterface.h" #include "TransportInterface.h"
#include "CommandParserInterface.h" #include "CommandParserInterface.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#define COMMAND_DELINATOR ' ' #define COMMAND_DELINATOR ' '
#define COMMAND_DELINATOR_TOGGLE '"' #define COMMAND_DELINATOR_TOGGLE '"'
#include "LinuxStrings.h" #include "LinuxStrings.h"
using namespace RakNet; using namespace RakNet;
STATIC_FACTORY_DEFINITIONS(ConsoleServer,ConsoleServer); STATIC_FACTORY_DEFINITIONS(ConsoleServer,ConsoleServer);
ConsoleServer::ConsoleServer() ConsoleServer::ConsoleServer()
{ {
transport=0; transport=0;
password[0]=0; password[0]=0;
prompt=0; prompt=0;
} }
ConsoleServer::~ConsoleServer() ConsoleServer::~ConsoleServer()
{ {
if (prompt) if (prompt)
rakFree_Ex(prompt, _FILE_AND_LINE_); rakFree_Ex(prompt, _FILE_AND_LINE_);
} }
void ConsoleServer::SetTransportProvider(TransportInterface *transportInterface, unsigned short port) void ConsoleServer::SetTransportProvider(TransportInterface *transportInterface, unsigned short port)
{ {
// Replace the current TransportInterface, stopping the old one, if present, and starting the new one. // Replace the current TransportInterface, stopping the old one, if present, and starting the new one.
if (transportInterface) if (transportInterface)
{ {
if (transport) if (transport)
{ {
RemoveCommandParser(transport->GetCommandParser()); RemoveCommandParser(transport->GetCommandParser());
transport->Stop(); transport->Stop();
} }
transport=transportInterface; transport=transportInterface;
transport->Start(port, true); transport->Start(port, true);
unsigned i; unsigned i;
for (i=0; i < commandParserList.Size(); i++) for (i=0; i < commandParserList.Size(); i++)
commandParserList[i]->OnTransportChange(transport); commandParserList[i]->OnTransportChange(transport);
// The transport itself might have a command parser - for example password for the RakNet transport // The transport itself might have a command parser - for example password for the RakNet transport
AddCommandParser(transport->GetCommandParser()); AddCommandParser(transport->GetCommandParser());
} }
} }
void ConsoleServer::AddCommandParser(CommandParserInterface *commandParserInterface) void ConsoleServer::AddCommandParser(CommandParserInterface *commandParserInterface)
{ {
if (commandParserInterface==0) if (commandParserInterface==0)
return; return;
// Non-duplicate insertion // Non-duplicate insertion
unsigned i; unsigned i;
for (i=0; i < commandParserList.Size(); i++) for (i=0; i < commandParserList.Size(); i++)
{ {
if (commandParserList[i]==commandParserInterface) if (commandParserList[i]==commandParserInterface)
return; return;
if (_stricmp(commandParserList[i]->GetName(), commandParserInterface->GetName())==0) if (_stricmp(commandParserList[i]->GetName(), commandParserInterface->GetName())==0)
{ {
// Naming conflict between two command parsers // Naming conflict between two command parsers
RakAssert(0); RakAssert(0);
return; return;
} }
} }
commandParserList.Insert(commandParserInterface, _FILE_AND_LINE_); commandParserList.Insert(commandParserInterface, _FILE_AND_LINE_);
if (transport) if (transport)
commandParserInterface->OnTransportChange(transport); commandParserInterface->OnTransportChange(transport);
} }
void ConsoleServer::RemoveCommandParser(CommandParserInterface *commandParserInterface) void ConsoleServer::RemoveCommandParser(CommandParserInterface *commandParserInterface)
{ {
if (commandParserInterface==0) if (commandParserInterface==0)
return; return;
// Overwrite the element we are removing from the back of the list and delete the back of the list // Overwrite the element we are removing from the back of the list and delete the back of the list
unsigned i; unsigned i;
for (i=0; i < commandParserList.Size(); i++) for (i=0; i < commandParserList.Size(); i++)
{ {
if (commandParserList[i]==commandParserInterface) if (commandParserList[i]==commandParserInterface)
{ {
commandParserList[i]=commandParserList[commandParserList.Size()-1]; commandParserList[i]=commandParserList[commandParserList.Size()-1];
commandParserList.RemoveFromEnd(); commandParserList.RemoveFromEnd();
return; return;
} }
} }
} }
void ConsoleServer::Update(void) void ConsoleServer::Update(void)
{ {
unsigned i; unsigned i;
char *parameterList[20]; // Up to 20 parameters char *parameterList[20]; // Up to 20 parameters
unsigned numParameters; unsigned numParameters;
RakNet::SystemAddress newOrLostConnectionId; RakNet::SystemAddress newOrLostConnectionId;
RakNet::Packet *p; RakNet::Packet *p;
RakNet::RegisteredCommand rc; RakNet::RegisteredCommand rc;
p = transport->Receive(); p = transport->Receive();
newOrLostConnectionId=transport->HasNewIncomingConnection(); newOrLostConnectionId=transport->HasNewIncomingConnection();
if (newOrLostConnectionId!=UNASSIGNED_SYSTEM_ADDRESS) if (newOrLostConnectionId!=UNASSIGNED_SYSTEM_ADDRESS)
{ {
for (i=0; i < commandParserList.Size(); i++) for (i=0; i < commandParserList.Size(); i++)
{ {
commandParserList[i]->OnNewIncomingConnection(newOrLostConnectionId, transport); commandParserList[i]->OnNewIncomingConnection(newOrLostConnectionId, transport);
} }
transport->Send(newOrLostConnectionId, "Connected to remote command console.\r\nType 'help' for help.\r\n"); transport->Send(newOrLostConnectionId, "Connected to remote command console.\r\nType 'help' for help.\r\n");
ListParsers(newOrLostConnectionId); ListParsers(newOrLostConnectionId);
ShowPrompt(newOrLostConnectionId); ShowPrompt(newOrLostConnectionId);
} }
newOrLostConnectionId=transport->HasLostConnection(); newOrLostConnectionId=transport->HasLostConnection();
if (newOrLostConnectionId!=UNASSIGNED_SYSTEM_ADDRESS) if (newOrLostConnectionId!=UNASSIGNED_SYSTEM_ADDRESS)
{ {
for (i=0; i < commandParserList.Size(); i++) for (i=0; i < commandParserList.Size(); i++)
commandParserList[i]->OnConnectionLost(newOrLostConnectionId, transport); commandParserList[i]->OnConnectionLost(newOrLostConnectionId, transport);
} }
while (p) while (p)
{ {
bool commandParsed=false; bool commandParsed=false;
char copy[REMOTE_MAX_TEXT_INPUT]; char copy[REMOTE_MAX_TEXT_INPUT];
memcpy(copy, p->data, p->length); memcpy(copy, p->data, p->length);
copy[p->length]=0; copy[p->length]=0;
RakNet::CommandParserInterface::ParseConsoleString((char*)p->data, COMMAND_DELINATOR, COMMAND_DELINATOR_TOGGLE, &numParameters, parameterList, 20); // Up to 20 parameters RakNet::CommandParserInterface::ParseConsoleString((char*)p->data, COMMAND_DELINATOR, COMMAND_DELINATOR_TOGGLE, &numParameters, parameterList, 20); // Up to 20 parameters
if (numParameters==0) if (numParameters==0)
{ {
transport->DeallocatePacket(p); transport->DeallocatePacket(p);
p = transport->Receive(); p = transport->Receive();
continue; continue;
} }
if (_stricmp(*parameterList, "help")==0 && numParameters<=2) if (_stricmp(*parameterList, "help")==0 && numParameters<=2)
{ {
// Find the parser specified and display help for it // Find the parser specified and display help for it
if (numParameters==1) if (numParameters==1)
{ {
transport->Send(p->systemAddress, "\r\nINSTRUCTIONS:\r\n"); transport->Send(p->systemAddress, "\r\nINSTRUCTIONS:\r\n");
transport->Send(p->systemAddress, "Enter commands on your keyboard, using spaces to delineate parameters.\r\n"); transport->Send(p->systemAddress, "Enter commands on your keyboard, using spaces to delineate parameters.\r\n");
transport->Send(p->systemAddress, "You can use quotation marks to toggle space delineation.\r\n"); transport->Send(p->systemAddress, "You can use quotation marks to toggle space delineation.\r\n");
transport->Send(p->systemAddress, "You can connect multiple times from the same computer.\r\n"); transport->Send(p->systemAddress, "You can connect multiple times from the same computer.\r\n");
transport->Send(p->systemAddress, "You can direct commands to a parser by prefixing the parser name or number.\r\n"); transport->Send(p->systemAddress, "You can direct commands to a parser by prefixing the parser name or number.\r\n");
transport->Send(p->systemAddress, "COMMANDS:\r\n"); transport->Send(p->systemAddress, "COMMANDS:\r\n");
transport->Send(p->systemAddress, "help Show this display.\r\n"); transport->Send(p->systemAddress, "help Show this display.\r\n");
transport->Send(p->systemAddress, "help <ParserName> Show help on a particular parser.\r\n"); transport->Send(p->systemAddress, "help <ParserName> Show help on a particular parser.\r\n");
transport->Send(p->systemAddress, "help <CommandName> Show help on a particular command.\r\n"); transport->Send(p->systemAddress, "help <CommandName> Show help on a particular command.\r\n");
transport->Send(p->systemAddress, "quit Disconnects from the server.\r\n"); transport->Send(p->systemAddress, "quit Disconnects from the server.\r\n");
transport->Send(p->systemAddress, "[<ParserName>] <Command> [<Parameters>] Execute a command\r\n"); transport->Send(p->systemAddress, "[<ParserName>] <Command> [<Parameters>] Execute a command\r\n");
transport->Send(p->systemAddress, "[<ParserNumber>] <Command> [<Parameters>] Execute a command\r\n"); transport->Send(p->systemAddress, "[<ParserNumber>] <Command> [<Parameters>] Execute a command\r\n");
ListParsers(p->systemAddress); ListParsers(p->systemAddress);
//ShowPrompt(p->systemAddress); //ShowPrompt(p->systemAddress);
} }
else // numParameters == 2, including the help tag else // numParameters == 2, including the help tag
{ {
for (i=0; i < commandParserList.Size(); i++) for (i=0; i < commandParserList.Size(); i++)
{ {
if (_stricmp(parameterList[1], commandParserList[i]->GetName())==0) if (_stricmp(parameterList[1], commandParserList[i]->GetName())==0)
{ {
commandParsed=true; commandParsed=true;
commandParserList[i]->SendHelp(transport, p->systemAddress); commandParserList[i]->SendHelp(transport, p->systemAddress);
transport->Send(p->systemAddress, "COMMAND LIST:\r\n"); transport->Send(p->systemAddress, "COMMAND LIST:\r\n");
commandParserList[i]->SendCommandList(transport, p->systemAddress); commandParserList[i]->SendCommandList(transport, p->systemAddress);
transport->Send(p->systemAddress, "\r\n"); transport->Send(p->systemAddress, "\r\n");
break; break;
} }
} }
if (commandParsed==false) if (commandParsed==false)
{ {
// Try again, for all commands for all parsers. // Try again, for all commands for all parsers.
RakNet::RegisteredCommand rc; RakNet::RegisteredCommand rc;
for (i=0; i < commandParserList.Size(); i++) for (i=0; i < commandParserList.Size(); i++)
{ {
if (commandParserList[i]->GetRegisteredCommand(parameterList[1], &rc)) if (commandParserList[i]->GetRegisteredCommand(parameterList[1], &rc))
{ {
if (rc.parameterCount==RakNet::CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS) if (rc.parameterCount==RakNet::CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS)
transport->Send(p->systemAddress, "(Variable parms): %s %s\r\n", rc.command, rc.commandHelp); transport->Send(p->systemAddress, "(Variable parms): %s %s\r\n", rc.command, rc.commandHelp);
else else
transport->Send(p->systemAddress, "(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp); transport->Send(p->systemAddress, "(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp);
commandParsed=true; commandParsed=true;
break; break;
} }
} }
} }
if (commandParsed==false) if (commandParsed==false)
{ {
// Don't know what to do // Don't know what to do
transport->Send(p->systemAddress, "Unknown help topic: %s.\r\n", parameterList[1]); transport->Send(p->systemAddress, "Unknown help topic: %s.\r\n", parameterList[1]);
} }
//ShowPrompt(p->systemAddress); //ShowPrompt(p->systemAddress);
} }
} }
else if (_stricmp(*parameterList, "quit")==0 && numParameters==1) else if (_stricmp(*parameterList, "quit")==0 && numParameters==1)
{ {
transport->Send(p->systemAddress, "Goodbye!\r\n"); transport->Send(p->systemAddress, "Goodbye!\r\n");
transport->CloseConnection(p->systemAddress); transport->CloseConnection(p->systemAddress);
} }
else else
{ {
bool tryAllParsers=true; bool tryAllParsers=true;
bool failed=false; bool failed=false;
if (numParameters >=2) // At minimum <CommandParserName> <Command> if (numParameters >=2) // At minimum <CommandParserName> <Command>
{ {
unsigned commandParserIndex=(unsigned)-1; unsigned commandParserIndex=(unsigned)-1;
// Prefixing with numbers directs to a particular parser // Prefixing with numbers directs to a particular parser
if (**parameterList>='0' && **parameterList<='9') if (**parameterList>='0' && **parameterList<='9')
{ {
commandParserIndex=atoi(*parameterList); // Use specified parser unless it's an invalid number commandParserIndex=atoi(*parameterList); // Use specified parser unless it's an invalid number
commandParserIndex--; // Subtract 1 since we displayed numbers starting at index+1 commandParserIndex--; // Subtract 1 since we displayed numbers starting at index+1
if (commandParserIndex >= commandParserList.Size()) if (commandParserIndex >= commandParserList.Size())
{ {
transport->Send(p->systemAddress, "Invalid index.\r\n"); transport->Send(p->systemAddress, "Invalid index.\r\n");
failed=true; failed=true;
} }
} }
else else
{ {
// // Prefixing with the name of a command parser directs to that parser. See if the first word matches a parser // // Prefixing with the name of a command parser directs to that parser. See if the first word matches a parser
for (i=0; i < commandParserList.Size(); i++) for (i=0; i < commandParserList.Size(); i++)
{ {
if (_stricmp(parameterList[0], commandParserList[i]->GetName())==0) if (_stricmp(parameterList[0], commandParserList[i]->GetName())==0)
{ {
commandParserIndex=i; // Matches parser at index i commandParserIndex=i; // Matches parser at index i
break; break;
} }
} }
} }
if (failed==false) if (failed==false)
{ {
// -1 means undirected, so otherwise this is directed to a target // -1 means undirected, so otherwise this is directed to a target
if (commandParserIndex!=(unsigned)-1) if (commandParserIndex!=(unsigned)-1)
{ {
// Only this parser should use this command // Only this parser should use this command
tryAllParsers=false; tryAllParsers=false;
if (commandParserList[commandParserIndex]->GetRegisteredCommand(parameterList[1], &rc)) if (commandParserList[commandParserIndex]->GetRegisteredCommand(parameterList[1], &rc))
{ {
commandParsed=true; commandParsed=true;
if (rc.parameterCount==CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS || rc.parameterCount==numParameters-2) if (rc.parameterCount==CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS || rc.parameterCount==numParameters-2)
commandParserList[commandParserIndex]->OnCommand(rc.command, numParameters-2, parameterList+2, transport, p->systemAddress, copy); commandParserList[commandParserIndex]->OnCommand(rc.command, numParameters-2, parameterList+2, transport, p->systemAddress, copy);
else else
transport->Send(p->systemAddress, "Invalid parameter count.\r\n(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp); transport->Send(p->systemAddress, "Invalid parameter count.\r\n(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp);
} }
} }
} }
} }
if (failed == false && tryAllParsers) if (failed == false && tryAllParsers)
{ {
for (i=0; i < commandParserList.Size(); i++) for (i=0; i < commandParserList.Size(); i++)
{ {
// Undirected command. Try all the parsers to see if they understand the command // Undirected command. Try all the parsers to see if they understand the command
// Pass the 1nd element as the command, and the remainder as the parameter list // Pass the 1nd element as the command, and the remainder as the parameter list
if (commandParserList[i]->GetRegisteredCommand(parameterList[0], &rc)) if (commandParserList[i]->GetRegisteredCommand(parameterList[0], &rc))
{ {
commandParsed=true; commandParsed=true;
if (rc.parameterCount==CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS || rc.parameterCount==numParameters-1) if (rc.parameterCount==CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS || rc.parameterCount==numParameters-1)
commandParserList[i]->OnCommand(rc.command, numParameters-1, parameterList+1, transport, p->systemAddress, copy); commandParserList[i]->OnCommand(rc.command, numParameters-1, parameterList+1, transport, p->systemAddress, copy);
else else
transport->Send(p->systemAddress, "Invalid parameter count.\r\n(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp); transport->Send(p->systemAddress, "Invalid parameter count.\r\n(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp);
} }
} }
} }
if (commandParsed==false && commandParserList.Size() > 0) if (commandParsed==false && commandParserList.Size() > 0)
{ {
transport->Send(p->systemAddress, "Unknown command: Type 'help' for help.\r\n"); transport->Send(p->systemAddress, "Unknown command: Type 'help' for help.\r\n");
} }
} }
ShowPrompt(p->systemAddress); ShowPrompt(p->systemAddress);
transport->DeallocatePacket(p); transport->DeallocatePacket(p);
p = transport->Receive(); p = transport->Receive();
} }
} }
void ConsoleServer::ListParsers(SystemAddress systemAddress) void ConsoleServer::ListParsers(SystemAddress systemAddress)
{ {
transport->Send(systemAddress,"INSTALLED PARSERS:\r\n"); transport->Send(systemAddress,"INSTALLED PARSERS:\r\n");
unsigned i; unsigned i;
for (i=0; i < commandParserList.Size(); i++) for (i=0; i < commandParserList.Size(); i++)
{ {
transport->Send(systemAddress, "%i. %s\r\n", i+1, commandParserList[i]->GetName()); transport->Send(systemAddress, "%i. %s\r\n", i+1, commandParserList[i]->GetName());
} }
} }
void ConsoleServer::ShowPrompt(SystemAddress systemAddress) void ConsoleServer::ShowPrompt(SystemAddress systemAddress)
{ {
transport->Send(systemAddress, prompt); transport->Send(systemAddress, prompt);
} }
void ConsoleServer::SetPrompt(const char *_prompt) void ConsoleServer::SetPrompt(const char *_prompt)
{ {
if (prompt) if (prompt)
rakFree_Ex(prompt,_FILE_AND_LINE_); rakFree_Ex(prompt,_FILE_AND_LINE_);
if (_prompt && _prompt[0]) if (_prompt && _prompt[0])
{ {
size_t len = strlen(_prompt); size_t len = strlen(_prompt);
prompt = (char*) rakMalloc_Ex(len+1,_FILE_AND_LINE_); prompt = (char*) rakMalloc_Ex(len+1,_FILE_AND_LINE_);
strcpy(prompt,_prompt); strcpy(prompt,_prompt);
} }
else else
prompt=0; prompt=0;
} }
#endif // _RAKNET_SUPPORT_* #endif // _RAKNET_SUPPORT_*

View File

@@ -1,77 +1,77 @@
/// \file ConsoleServer.h /// \file ConsoleServer.h
/// \brief Contains ConsoleServer , used to plugin to your game to accept remote console-based connections /// \brief Contains ConsoleServer , used to plugin to your game to accept remote console-based connections
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_ConsoleServer==1 #if _RAKNET_SUPPORT_ConsoleServer==1
#ifndef __CONSOLE_SERVER_H #ifndef __CONSOLE_SERVER_H
#define __CONSOLE_SERVER_H #define __CONSOLE_SERVER_H
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "DS_List.h" #include "DS_List.h"
#include "RakNetTypes.h" #include "RakNetTypes.h"
#include "Export.h" #include "Export.h"
namespace RakNet namespace RakNet
{ {
/// Forward declarations /// Forward declarations
class TransportInterface; class TransportInterface;
class CommandParserInterface; class CommandParserInterface;
/// \brief The main entry point for the server portion of your remote console application support. /// \brief The main entry point for the server portion of your remote console application support.
/// \details ConsoleServer takes one TransportInterface and one or more CommandParserInterface (s) /// \details ConsoleServer takes one TransportInterface and one or more CommandParserInterface (s)
/// The TransportInterface will be used to send data between the server and the client. The connecting client must support the /// The TransportInterface will be used to send data between the server and the client. The connecting client must support the
/// protocol used by your derivation of TransportInterface . TelnetTransport and RakNetTransport are two such derivations . /// protocol used by your derivation of TransportInterface . TelnetTransport and RakNetTransport are two such derivations .
/// When a command is sent by a remote console, it will be processed by your implementations of CommandParserInterface /// When a command is sent by a remote console, it will be processed by your implementations of CommandParserInterface
class RAK_DLL_EXPORT ConsoleServer class RAK_DLL_EXPORT ConsoleServer
{ {
public: public:
// GetInstance() and DestroyInstance(instance*) // GetInstance() and DestroyInstance(instance*)
STATIC_FACTORY_DECLARATIONS(ConsoleServer) STATIC_FACTORY_DECLARATIONS(ConsoleServer)
ConsoleServer(); ConsoleServer();
~ConsoleServer(); ~ConsoleServer();
/// \brief Call this with a derivation of TransportInterface so that the console server can send and receive commands /// \brief Call this with a derivation of TransportInterface so that the console server can send and receive commands
/// \param[in] transportInterface Your interface to use. /// \param[in] transportInterface Your interface to use.
/// \param[in] port The port to host on. Telnet uses port 23 by default. RakNet can use whatever you want. /// \param[in] port The port to host on. Telnet uses port 23 by default. RakNet can use whatever you want.
void SetTransportProvider(TransportInterface *transportInterface, unsigned short port); void SetTransportProvider(TransportInterface *transportInterface, unsigned short port);
/// \brief Add an implementation of CommandParserInterface to the list of command parsers. /// \brief Add an implementation of CommandParserInterface to the list of command parsers.
/// \param[in] commandParserInterface The command parser referred to /// \param[in] commandParserInterface The command parser referred to
void AddCommandParser(CommandParserInterface *commandParserInterface); void AddCommandParser(CommandParserInterface *commandParserInterface);
/// \brief Remove an implementation of CommandParserInterface previously added with AddCommandParser(). /// \brief Remove an implementation of CommandParserInterface previously added with AddCommandParser().
/// \param[in] commandParserInterface The command parser referred to /// \param[in] commandParserInterface The command parser referred to
void RemoveCommandParser(CommandParserInterface *commandParserInterface); void RemoveCommandParser(CommandParserInterface *commandParserInterface);
/// \brief Call update to read packet sent from your TransportInterface. /// \brief Call update to read packet sent from your TransportInterface.
/// You should do this fairly frequently. /// You should do this fairly frequently.
void Update(void); void Update(void);
/// \brief Sets a prompt to show when waiting for user input. /// \brief Sets a prompt to show when waiting for user input.
/// \details Pass an empty string to clear the prompt /// \details Pass an empty string to clear the prompt
/// Defaults to no prompt /// Defaults to no prompt
/// \param[in] _prompt Null-terminated string of the prompt to use. If you want a newline, be sure to use /r/n /// \param[in] _prompt Null-terminated string of the prompt to use. If you want a newline, be sure to use /r/n
void SetPrompt(const char *_prompt); void SetPrompt(const char *_prompt);
protected: protected:
void ListParsers(SystemAddress systemAddress); void ListParsers(SystemAddress systemAddress);
void ShowPrompt(SystemAddress systemAddress); void ShowPrompt(SystemAddress systemAddress);
TransportInterface *transport; TransportInterface *transport;
DataStructures::List<CommandParserInterface *> commandParserList; DataStructures::List<CommandParserInterface *> commandParserList;
char* password[256]; char* password[256];
char *prompt; char *prompt;
}; };
} // namespace RakNet } // namespace RakNet
#endif #endif
#endif // _RAKNET_SUPPORT_* #endif // _RAKNET_SUPPORT_*

File diff suppressed because it is too large Load Diff

View File

@@ -1,149 +1,149 @@
#include "DS_BytePool.h" #include "DS_BytePool.h"
#include "RakAssert.h" #include "RakAssert.h"
#ifndef __APPLE__ #ifndef __APPLE__
// Use stdlib and not malloc for compatibility // Use stdlib and not malloc for compatibility
#include <stdlib.h> #include <stdlib.h>
#endif #endif
using namespace DataStructures; using namespace DataStructures;
BytePool::BytePool() BytePool::BytePool()
{ {
pool128.SetPageSize(8192*4); pool128.SetPageSize(8192*4);
pool512.SetPageSize(8192*4); pool512.SetPageSize(8192*4);
pool2048.SetPageSize(8192*4); pool2048.SetPageSize(8192*4);
pool8192.SetPageSize(8192*4); pool8192.SetPageSize(8192*4);
} }
BytePool::~BytePool() BytePool::~BytePool()
{ {
} }
void BytePool::SetPageSize(int size) void BytePool::SetPageSize(int size)
{ {
pool128.SetPageSize(size); pool128.SetPageSize(size);
pool512.SetPageSize(size); pool512.SetPageSize(size);
pool2048.SetPageSize(size); pool2048.SetPageSize(size);
pool8192.SetPageSize(size); pool8192.SetPageSize(size);
} }
unsigned char *BytePool::Allocate(int bytesWanted, const char *file, unsigned int line) unsigned char *BytePool::Allocate(int bytesWanted, const char *file, unsigned int line)
{ {
#ifdef _DISABLE_BYTE_POOL #ifdef _DISABLE_BYTE_POOL
return rakMalloc_Ex(bytesWanted, _FILE_AND_LINE_); return rakMalloc_Ex(bytesWanted, _FILE_AND_LINE_);
#endif #endif
unsigned char *out; unsigned char *out;
if (bytesWanted <= 127) if (bytesWanted <= 127)
{ {
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex128.Lock(); mutex128.Lock();
#endif #endif
out = (unsigned char*) pool128.Allocate(file, line); out = (unsigned char*) pool128.Allocate(file, line);
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex128.Unlock(); mutex128.Unlock();
#endif #endif
out[0]=0; out[0]=0;
return ((unsigned char*) out)+1; return ((unsigned char*) out)+1;
} }
if (bytesWanted <= 511) if (bytesWanted <= 511)
{ {
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex512.Lock(); mutex512.Lock();
#endif #endif
out = (unsigned char*) pool512.Allocate(file, line); out = (unsigned char*) pool512.Allocate(file, line);
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex512.Unlock(); mutex512.Unlock();
#endif #endif
out[0]=1; out[0]=1;
return ((unsigned char*) out)+1; return ((unsigned char*) out)+1;
} }
if (bytesWanted <= 2047) if (bytesWanted <= 2047)
{ {
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex2048.Lock(); mutex2048.Lock();
#endif #endif
out = (unsigned char*) pool2048.Allocate(file, line); out = (unsigned char*) pool2048.Allocate(file, line);
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex2048.Unlock(); mutex2048.Unlock();
#endif #endif
out[0]=2; out[0]=2;
return ((unsigned char*) out)+1; return ((unsigned char*) out)+1;
} }
if (bytesWanted <= 8191) if (bytesWanted <= 8191)
{ {
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex8192.Lock(); mutex8192.Lock();
#endif #endif
out = (unsigned char*) pool8192.Allocate(file, line); out = (unsigned char*) pool8192.Allocate(file, line);
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex8192.Unlock(); mutex8192.Unlock();
#endif #endif
out[0]=3; out[0]=3;
return ((unsigned char*) out)+1; return ((unsigned char*) out)+1;
} }
out = (unsigned char*) rakMalloc_Ex(bytesWanted+1, _FILE_AND_LINE_); out = (unsigned char*) rakMalloc_Ex(bytesWanted+1, _FILE_AND_LINE_);
out[0]=(unsigned char)255; out[0]=(unsigned char)255;
return out+1; return out+1;
} }
void BytePool::Release(unsigned char *data, const char *file, unsigned int line) void BytePool::Release(unsigned char *data, const char *file, unsigned int line)
{ {
#ifdef _DISABLE_BYTE_POOL #ifdef _DISABLE_BYTE_POOL
_rakFree_Ex(data, _FILE_AND_LINE_ ); _rakFree_Ex(data, _FILE_AND_LINE_ );
#endif #endif
unsigned char *realData = data-1; unsigned char *realData = data-1;
switch (realData[0]) switch (realData[0])
{ {
case 0: case 0:
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex128.Lock(); mutex128.Lock();
#endif #endif
pool128.Release((unsigned char(*)[128]) realData, file, line ); pool128.Release((unsigned char(*)[128]) realData, file, line );
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex128.Unlock(); mutex128.Unlock();
#endif #endif
break; break;
case 1: case 1:
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex512.Lock(); mutex512.Lock();
#endif #endif
pool512.Release((unsigned char(*)[512]) realData, file, line ); pool512.Release((unsigned char(*)[512]) realData, file, line );
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex512.Unlock(); mutex512.Unlock();
#endif #endif
break; break;
case 2: case 2:
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex2048.Lock(); mutex2048.Lock();
#endif #endif
pool2048.Release((unsigned char(*)[2048]) realData, file, line ); pool2048.Release((unsigned char(*)[2048]) realData, file, line );
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex2048.Unlock(); mutex2048.Unlock();
#endif #endif
break; break;
case 3: case 3:
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex8192.Lock(); mutex8192.Lock();
#endif #endif
pool8192.Release((unsigned char(*)[8192]) realData, file, line ); pool8192.Release((unsigned char(*)[8192]) realData, file, line );
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
mutex8192.Unlock(); mutex8192.Unlock();
#endif #endif
break; break;
case 255: case 255:
rakFree_Ex(realData, file, line ); rakFree_Ex(realData, file, line );
break; break;
default: default:
RakAssert(0); RakAssert(0);
break; break;
} }
} }
void BytePool::Clear(const char *file, unsigned int line) void BytePool::Clear(const char *file, unsigned int line)
{ {
(void) file; (void) file;
(void) line; (void) line;
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
pool128.Clear(file, line); pool128.Clear(file, line);
pool512.Clear(file, line); pool512.Clear(file, line);
pool2048.Clear(file, line); pool2048.Clear(file, line);
pool8192.Clear(file, line); pool8192.Clear(file, line);
#endif #endif
} }

View File

@@ -1,46 +1,46 @@
/// \file DS_BytePool.h /// \file DS_BytePool.h
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __BYTE_POOL_H #ifndef __BYTE_POOL_H
#define __BYTE_POOL_H #define __BYTE_POOL_H
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "DS_MemoryPool.h" #include "DS_MemoryPool.h"
#include "Export.h" #include "Export.h"
#include "SimpleMutex.h" #include "SimpleMutex.h"
#include "RakAssert.h" #include "RakAssert.h"
// #define _DISABLE_BYTE_POOL // #define _DISABLE_BYTE_POOL
// #define _THREADSAFE_BYTE_POOL // #define _THREADSAFE_BYTE_POOL
namespace DataStructures namespace DataStructures
{ {
// Allocate some number of bytes from pools. Uses the heap if necessary. // Allocate some number of bytes from pools. Uses the heap if necessary.
class RAK_DLL_EXPORT BytePool class RAK_DLL_EXPORT BytePool
{ {
public: public:
BytePool(); BytePool();
~BytePool(); ~BytePool();
// Should be at least 8 times bigger than 8192 // Should be at least 8 times bigger than 8192
void SetPageSize(int size); void SetPageSize(int size);
unsigned char* Allocate(int bytesWanted, const char *file, unsigned int line); unsigned char* Allocate(int bytesWanted, const char *file, unsigned int line);
void Release(unsigned char *data, const char *file, unsigned int line); void Release(unsigned char *data, const char *file, unsigned int line);
void Clear(const char *file, unsigned int line); void Clear(const char *file, unsigned int line);
protected: protected:
MemoryPool<unsigned char[128]> pool128; MemoryPool<unsigned char[128]> pool128;
MemoryPool<unsigned char[512]> pool512; MemoryPool<unsigned char[512]> pool512;
MemoryPool<unsigned char[2048]> pool2048; MemoryPool<unsigned char[2048]> pool2048;
MemoryPool<unsigned char[8192]> pool8192; MemoryPool<unsigned char[8192]> pool8192;
#ifdef _THREADSAFE_BYTE_POOL #ifdef _THREADSAFE_BYTE_POOL
SimpleMutex mutex128; SimpleMutex mutex128;
SimpleMutex mutex512; SimpleMutex mutex512;
SimpleMutex mutex2048; SimpleMutex mutex2048;
SimpleMutex mutex8192; SimpleMutex mutex8192;
#endif #endif
}; };
} }
#endif #endif

View File

@@ -1,127 +1,127 @@
#include "DS_ByteQueue.h" #include "DS_ByteQueue.h"
#include <string.h> // Memmove #include <string.h> // Memmove
#include <stdlib.h> // realloc #include <stdlib.h> // realloc
#include <stdio.h> #include <stdio.h>
using namespace DataStructures; using namespace DataStructures;
ByteQueue::ByteQueue() ByteQueue::ByteQueue()
{ {
readOffset=writeOffset=lengthAllocated=0; readOffset=writeOffset=lengthAllocated=0;
data=0; data=0;
} }
ByteQueue::~ByteQueue() ByteQueue::~ByteQueue()
{ {
Clear(_FILE_AND_LINE_); Clear(_FILE_AND_LINE_);
} }
void ByteQueue::WriteBytes(const char *in, unsigned length, const char *file, unsigned int line) void ByteQueue::WriteBytes(const char *in, unsigned length, const char *file, unsigned int line)
{ {
unsigned bytesWritten; unsigned bytesWritten;
bytesWritten=GetBytesWritten(); bytesWritten=GetBytesWritten();
if (lengthAllocated==0 || length > lengthAllocated-bytesWritten-1) if (lengthAllocated==0 || length > lengthAllocated-bytesWritten-1)
{ {
unsigned oldLengthAllocated=lengthAllocated; unsigned oldLengthAllocated=lengthAllocated;
// Always need to waste 1 byte for the math to work, else writeoffset==readoffset // Always need to waste 1 byte for the math to work, else writeoffset==readoffset
unsigned newAmountToAllocate=length+oldLengthAllocated+1; unsigned newAmountToAllocate=length+oldLengthAllocated+1;
if (newAmountToAllocate<256) if (newAmountToAllocate<256)
newAmountToAllocate=256; newAmountToAllocate=256;
lengthAllocated=lengthAllocated + newAmountToAllocate; lengthAllocated=lengthAllocated + newAmountToAllocate;
data=(char*)rakRealloc_Ex(data, lengthAllocated, file, line); data=(char*)rakRealloc_Ex(data, lengthAllocated, file, line);
if (writeOffset < readOffset) if (writeOffset < readOffset)
{ {
if (writeOffset <= newAmountToAllocate) if (writeOffset <= newAmountToAllocate)
{ {
memcpy(data + oldLengthAllocated, data, writeOffset); memcpy(data + oldLengthAllocated, data, writeOffset);
writeOffset=readOffset+bytesWritten; writeOffset=readOffset+bytesWritten;
} }
else else
{ {
memcpy(data + oldLengthAllocated, data, newAmountToAllocate); memcpy(data + oldLengthAllocated, data, newAmountToAllocate);
memmove(data, data+newAmountToAllocate, writeOffset-newAmountToAllocate); memmove(data, data+newAmountToAllocate, writeOffset-newAmountToAllocate);
writeOffset-=newAmountToAllocate; writeOffset-=newAmountToAllocate;
} }
} }
} }
if (length <= lengthAllocated-writeOffset) if (length <= lengthAllocated-writeOffset)
memcpy(data+writeOffset, in, length); memcpy(data+writeOffset, in, length);
else else
{ {
// Wrap // Wrap
memcpy(data+writeOffset, in, lengthAllocated-writeOffset); memcpy(data+writeOffset, in, lengthAllocated-writeOffset);
memcpy(data, in+(lengthAllocated-writeOffset), length-(lengthAllocated-writeOffset)); memcpy(data, in+(lengthAllocated-writeOffset), length-(lengthAllocated-writeOffset));
} }
writeOffset=(writeOffset+length) % lengthAllocated; writeOffset=(writeOffset+length) % lengthAllocated;
} }
bool ByteQueue::ReadBytes(char *out, unsigned maxLengthToRead, bool peek) bool ByteQueue::ReadBytes(char *out, unsigned maxLengthToRead, bool peek)
{ {
unsigned bytesWritten = GetBytesWritten(); unsigned bytesWritten = GetBytesWritten();
unsigned bytesToRead = bytesWritten < maxLengthToRead ? bytesWritten : maxLengthToRead; unsigned bytesToRead = bytesWritten < maxLengthToRead ? bytesWritten : maxLengthToRead;
if (bytesToRead==0) if (bytesToRead==0)
return false; return false;
if (writeOffset>=readOffset) if (writeOffset>=readOffset)
{ {
memcpy(out, data+readOffset, bytesToRead); memcpy(out, data+readOffset, bytesToRead);
} }
else else
{ {
unsigned availableUntilWrap = lengthAllocated-readOffset; unsigned availableUntilWrap = lengthAllocated-readOffset;
if (bytesToRead <= availableUntilWrap) if (bytesToRead <= availableUntilWrap)
{ {
memcpy(out, data+readOffset, bytesToRead); memcpy(out, data+readOffset, bytesToRead);
} }
else else
{ {
memcpy(out, data+readOffset, availableUntilWrap); memcpy(out, data+readOffset, availableUntilWrap);
memcpy(out+availableUntilWrap, data, bytesToRead-availableUntilWrap); memcpy(out+availableUntilWrap, data, bytesToRead-availableUntilWrap);
} }
} }
if (peek==false) if (peek==false)
IncrementReadOffset(bytesToRead); IncrementReadOffset(bytesToRead);
return true; return true;
} }
char* ByteQueue::PeekContiguousBytes(unsigned int *outLength) const char* ByteQueue::PeekContiguousBytes(unsigned int *outLength) const
{ {
if (writeOffset>=readOffset) if (writeOffset>=readOffset)
*outLength=writeOffset-readOffset; *outLength=writeOffset-readOffset;
else else
*outLength=lengthAllocated-readOffset; *outLength=lengthAllocated-readOffset;
return data+readOffset; return data+readOffset;
} }
void ByteQueue::Clear(const char *file, unsigned int line) void ByteQueue::Clear(const char *file, unsigned int line)
{ {
if (lengthAllocated) if (lengthAllocated)
rakFree_Ex(data, file, line ); rakFree_Ex(data, file, line );
readOffset=writeOffset=lengthAllocated=0; readOffset=writeOffset=lengthAllocated=0;
data=0; data=0;
} }
unsigned ByteQueue::GetBytesWritten(void) const unsigned ByteQueue::GetBytesWritten(void) const
{ {
if (writeOffset>=readOffset) if (writeOffset>=readOffset)
return writeOffset-readOffset; return writeOffset-readOffset;
else else
return writeOffset+(lengthAllocated-readOffset); return writeOffset+(lengthAllocated-readOffset);
} }
void ByteQueue::IncrementReadOffset(unsigned length) void ByteQueue::IncrementReadOffset(unsigned length)
{ {
readOffset=(readOffset+length) % lengthAllocated; readOffset=(readOffset+length) % lengthAllocated;
} }
void ByteQueue::DecrementReadOffset(unsigned length) void ByteQueue::DecrementReadOffset(unsigned length)
{ {
if (length>readOffset) if (length>readOffset)
readOffset=lengthAllocated-(length-readOffset); readOffset=lengthAllocated-(length-readOffset);
else else
readOffset-=length; readOffset-=length;
} }
void ByteQueue::Print(void) void ByteQueue::Print(void)
{ {
unsigned i; unsigned i;
for (i=readOffset; i!=writeOffset; i++) for (i=readOffset; i!=writeOffset; i++)
RAKNET_DEBUG_PRINTF("%i ", data[i]); RAKNET_DEBUG_PRINTF("%i ", data[i]);
RAKNET_DEBUG_PRINTF("\n"); RAKNET_DEBUG_PRINTF("\n");
} }

View File

@@ -1,40 +1,40 @@
/// \file DS_ByteQueue.h /// \file DS_ByteQueue.h
/// \internal /// \internal
/// \brief Byte queue /// \brief Byte queue
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __BYTE_QUEUE_H #ifndef __BYTE_QUEUE_H
#define __BYTE_QUEUE_H #define __BYTE_QUEUE_H
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "Export.h" #include "Export.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures namespace DataStructures
{ {
class ByteQueue class ByteQueue
{ {
public: public:
ByteQueue(); ByteQueue();
~ByteQueue(); ~ByteQueue();
void WriteBytes(const char *in, unsigned length, const char *file, unsigned int line); void WriteBytes(const char *in, unsigned length, const char *file, unsigned int line);
bool ReadBytes(char *out, unsigned maxLengthToRead, bool peek); bool ReadBytes(char *out, unsigned maxLengthToRead, bool peek);
unsigned GetBytesWritten(void) const; unsigned GetBytesWritten(void) const;
char* PeekContiguousBytes(unsigned int *outLength) const; char* PeekContiguousBytes(unsigned int *outLength) const;
void IncrementReadOffset(unsigned length); void IncrementReadOffset(unsigned length);
void DecrementReadOffset(unsigned length); void DecrementReadOffset(unsigned length);
void Clear(const char *file, unsigned int line); void Clear(const char *file, unsigned int line);
void Print(void); void Print(void);
protected: protected:
char *data; char *data;
unsigned readOffset, writeOffset, lengthAllocated; unsigned readOffset, writeOffset, lengthAllocated;
}; };
} }
#endif #endif

View File

@@ -1,344 +1,344 @@
/// \internal /// \internal
/// \brief Hashing container /// \brief Hashing container
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __HASH_H #ifndef __HASH_H
#define __HASH_H #define __HASH_H
#include "RakAssert.h" #include "RakAssert.h"
#include <string.h> // memmove #include <string.h> // memmove
#include "Export.h" #include "Export.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "RakString.h" #include "RakString.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures namespace DataStructures
{ {
struct HashIndex struct HashIndex
{ {
unsigned int primaryIndex; unsigned int primaryIndex;
unsigned int secondaryIndex; unsigned int secondaryIndex;
bool IsInvalid(void) const {return primaryIndex==(unsigned int) -1;} bool IsInvalid(void) const {return primaryIndex==(unsigned int) -1;}
void SetInvalid(void) {primaryIndex=(unsigned int) -1; secondaryIndex=(unsigned int) -1;} void SetInvalid(void) {primaryIndex=(unsigned int) -1; secondaryIndex=(unsigned int) -1;}
}; };
/// \brief Using a string as a identifier for a node, store an allocated pointer to that node /// \brief Using a string as a identifier for a node, store an allocated pointer to that node
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
class RAK_DLL_EXPORT Hash class RAK_DLL_EXPORT Hash
{ {
public: public:
/// Default constructor /// Default constructor
Hash(); Hash();
// Destructor // Destructor
~Hash(); ~Hash();
void Push(key_type key, const data_type &input, const char *file, unsigned int line ); void Push(key_type key, const data_type &input, const char *file, unsigned int line );
data_type* Peek(key_type key ); data_type* Peek(key_type key );
bool Pop(data_type& out, key_type key, const char *file, unsigned int line ); bool Pop(data_type& out, key_type key, const char *file, unsigned int line );
bool RemoveAtIndex(HashIndex index, const char *file, unsigned int line ); bool RemoveAtIndex(HashIndex index, const char *file, unsigned int line );
bool Remove(key_type key, const char *file, unsigned int line ); bool Remove(key_type key, const char *file, unsigned int line );
HashIndex GetIndexOf(key_type key); HashIndex GetIndexOf(key_type key);
bool HasData(key_type key); bool HasData(key_type key);
data_type& ItemAtIndex(const HashIndex &index); data_type& ItemAtIndex(const HashIndex &index);
key_type KeyAtIndex(const HashIndex &index); key_type KeyAtIndex(const HashIndex &index);
void GetAsList(DataStructures::List<data_type> &itemList,DataStructures::List<key_type > &keyList,const char *file, unsigned int line) const; void GetAsList(DataStructures::List<data_type> &itemList,DataStructures::List<key_type > &keyList,const char *file, unsigned int line) const;
unsigned int Size(void) const; unsigned int Size(void) const;
/// \brief Clear the list /// \brief Clear the list
void Clear( const char *file, unsigned int line ); void Clear( const char *file, unsigned int line );
struct Node struct Node
{ {
Node(key_type strIn, const data_type &_data) {string=strIn; data=_data;} Node(key_type strIn, const data_type &_data) {string=strIn; data=_data;}
key_type string; key_type string;
data_type data; data_type data;
// Next in the list for this key // Next in the list for this key
Node *next; Node *next;
}; };
protected: protected:
void ClearIndex(unsigned int index,const char *file, unsigned int line); void ClearIndex(unsigned int index,const char *file, unsigned int line);
Node **nodeList; Node **nodeList;
unsigned int size; unsigned int size;
}; };
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
Hash<key_type, data_type, HASH_SIZE, hashFunction>::Hash() Hash<key_type, data_type, HASH_SIZE, hashFunction>::Hash()
{ {
nodeList=0; nodeList=0;
size=0; size=0;
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
Hash<key_type, data_type, HASH_SIZE, hashFunction>::~Hash() Hash<key_type, data_type, HASH_SIZE, hashFunction>::~Hash()
{ {
Clear(_FILE_AND_LINE_); Clear(_FILE_AND_LINE_);
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Push(key_type key, const data_type &input, const char *file, unsigned int line ) void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Push(key_type key, const data_type &input, const char *file, unsigned int line )
{ {
unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE; unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
if (nodeList==0) if (nodeList==0)
{ {
nodeList=RakNet::OP_NEW_ARRAY<Node *>(HASH_SIZE,file,line); nodeList=RakNet::OP_NEW_ARRAY<Node *>(HASH_SIZE,file,line);
memset(nodeList,0,sizeof(Node *)*HASH_SIZE); memset(nodeList,0,sizeof(Node *)*HASH_SIZE);
} }
Node *newNode=RakNet::OP_NEW_2<Node>(file,line,key,input); Node *newNode=RakNet::OP_NEW_2<Node>(file,line,key,input);
newNode->next=nodeList[hashIndex]; newNode->next=nodeList[hashIndex];
nodeList[hashIndex]=newNode; nodeList[hashIndex]=newNode;
size++; size++;
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
data_type* Hash<key_type, data_type, HASH_SIZE, hashFunction>::Peek(key_type key ) data_type* Hash<key_type, data_type, HASH_SIZE, hashFunction>::Peek(key_type key )
{ {
unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE; unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
Node *node = nodeList[hashIndex]; Node *node = nodeList[hashIndex];
while (node!=0) while (node!=0)
{ {
if (node->string==key) if (node->string==key)
return &node->data; return &node->data;
node=node->next; node=node->next;
} }
return 0; return 0;
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Pop(data_type& out, key_type key, const char *file, unsigned int line ) bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Pop(data_type& out, key_type key, const char *file, unsigned int line )
{ {
unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE; unsigned long hashIndex = (*hashFunction)(key) % HASH_SIZE;
Node *node = nodeList[hashIndex]; Node *node = nodeList[hashIndex];
if (node==0) if (node==0)
return false; return false;
if (node->next==0) if (node->next==0)
{ {
// Only one item. // Only one item.
if (node->string==key) if (node->string==key)
{ {
// Delete last item // Delete last item
out=node->data; out=node->data;
ClearIndex(hashIndex,_FILE_AND_LINE_); ClearIndex(hashIndex,_FILE_AND_LINE_);
return true; return true;
} }
else else
{ {
// Single item doesn't match // Single item doesn't match
return false; return false;
} }
} }
else if (node->string==key) else if (node->string==key)
{ {
// First item does match, but more than one item // First item does match, but more than one item
out=node->data; out=node->data;
nodeList[hashIndex]=node->next; nodeList[hashIndex]=node->next;
RakNet::OP_DELETE(node,file,line); RakNet::OP_DELETE(node,file,line);
size--; size--;
return true; return true;
} }
Node *last=node; Node *last=node;
node=node->next; node=node->next;
while (node!=0) while (node!=0)
{ {
// First item does not match, but subsequent item might // First item does not match, but subsequent item might
if (node->string==key) if (node->string==key)
{ {
out=node->data; out=node->data;
// Skip over subsequent item // Skip over subsequent item
last->next=node->next; last->next=node->next;
// Delete existing item // Delete existing item
RakNet::OP_DELETE(node,file,line); RakNet::OP_DELETE(node,file,line);
size--; size--;
return true; return true;
} }
last=node; last=node;
node=node->next; node=node->next;
} }
return false; return false;
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::RemoveAtIndex(HashIndex index, const char *file, unsigned int line ) bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::RemoveAtIndex(HashIndex index, const char *file, unsigned int line )
{ {
if (index.IsInvalid()) if (index.IsInvalid())
return false; return false;
Node *node = nodeList[index.primaryIndex]; Node *node = nodeList[index.primaryIndex];
if (node==0) if (node==0)
return false; return false;
if (node->next==0) if (node->next==0)
{ {
// Delete last item // Delete last item
ClearIndex(index.primaryIndex,file,line); ClearIndex(index.primaryIndex,file,line);
return true; return true;
} }
else if (index.secondaryIndex==0) else if (index.secondaryIndex==0)
{ {
// First item does match, but more than one item // First item does match, but more than one item
nodeList[index.primaryIndex]=node->next; nodeList[index.primaryIndex]=node->next;
RakNet::OP_DELETE(node,file,line); RakNet::OP_DELETE(node,file,line);
size--; size--;
return true; return true;
} }
Node *last=node; Node *last=node;
node=node->next; node=node->next;
--index.secondaryIndex; --index.secondaryIndex;
while (index.secondaryIndex!=0) while (index.secondaryIndex!=0)
{ {
last=node; last=node;
node=node->next; node=node->next;
--index.secondaryIndex; --index.secondaryIndex;
} }
// Skip over subsequent item // Skip over subsequent item
last->next=node->next; last->next=node->next;
// Delete existing item // Delete existing item
RakNet::OP_DELETE(node,file,line); RakNet::OP_DELETE(node,file,line);
size--; size--;
return true; return true;
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Remove(key_type key, const char *file, unsigned int line ) bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::Remove(key_type key, const char *file, unsigned int line )
{ {
return RemoveAtIndex(GetIndexOf(key),file,line); return RemoveAtIndex(GetIndexOf(key),file,line);
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
HashIndex Hash<key_type, data_type, HASH_SIZE, hashFunction>::GetIndexOf(key_type key) HashIndex Hash<key_type, data_type, HASH_SIZE, hashFunction>::GetIndexOf(key_type key)
{ {
if (nodeList==0) if (nodeList==0)
{ {
HashIndex temp; HashIndex temp;
temp.SetInvalid(); temp.SetInvalid();
return temp; return temp;
} }
HashIndex idx; HashIndex idx;
idx.primaryIndex=(*hashFunction)(key) % HASH_SIZE; idx.primaryIndex=(*hashFunction)(key) % HASH_SIZE;
Node *node = nodeList[idx.primaryIndex]; Node *node = nodeList[idx.primaryIndex];
if (node==0) if (node==0)
{ {
idx.SetInvalid(); idx.SetInvalid();
return idx; return idx;
} }
idx.secondaryIndex=0; idx.secondaryIndex=0;
while (node!=0) while (node!=0)
{ {
if (node->string==key) if (node->string==key)
{ {
return idx; return idx;
} }
node=node->next; node=node->next;
idx.secondaryIndex++; idx.secondaryIndex++;
} }
idx.SetInvalid(); idx.SetInvalid();
return idx; return idx;
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::HasData(key_type key) bool Hash<key_type, data_type, HASH_SIZE, hashFunction>::HasData(key_type key)
{ {
return GetIndexOf(key).IsInvalid()==false; return GetIndexOf(key).IsInvalid()==false;
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
data_type& Hash<key_type, data_type, HASH_SIZE, hashFunction>::ItemAtIndex(const HashIndex &index) data_type& Hash<key_type, data_type, HASH_SIZE, hashFunction>::ItemAtIndex(const HashIndex &index)
{ {
Node *node = nodeList[index.primaryIndex]; Node *node = nodeList[index.primaryIndex];
RakAssert(node); RakAssert(node);
unsigned int i; unsigned int i;
for (i=0; i < index.secondaryIndex; i++) for (i=0; i < index.secondaryIndex; i++)
{ {
node=node->next; node=node->next;
RakAssert(node); RakAssert(node);
} }
return node->data; return node->data;
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
key_type Hash<key_type, data_type, HASH_SIZE, hashFunction>::KeyAtIndex(const HashIndex &index) key_type Hash<key_type, data_type, HASH_SIZE, hashFunction>::KeyAtIndex(const HashIndex &index)
{ {
Node *node = nodeList[index.primaryIndex]; Node *node = nodeList[index.primaryIndex];
RakAssert(node); RakAssert(node);
unsigned int i; unsigned int i;
for (i=0; i < index.secondaryIndex; i++) for (i=0; i < index.secondaryIndex; i++)
{ {
node=node->next; node=node->next;
RakAssert(node); RakAssert(node);
} }
return node->string; return node->string;
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Clear(const char *file, unsigned int line) void Hash<key_type, data_type, HASH_SIZE, hashFunction>::Clear(const char *file, unsigned int line)
{ {
if (nodeList) if (nodeList)
{ {
unsigned int i; unsigned int i;
for (i=0; i < HASH_SIZE; i++) for (i=0; i < HASH_SIZE; i++)
ClearIndex(i,file,line); ClearIndex(i,file,line);
RakNet::OP_DELETE_ARRAY(nodeList,file,line); RakNet::OP_DELETE_ARRAY(nodeList,file,line);
nodeList=0; nodeList=0;
size=0; size=0;
} }
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
void Hash<key_type, data_type, HASH_SIZE, hashFunction>::ClearIndex(unsigned int index,const char *file, unsigned int line) void Hash<key_type, data_type, HASH_SIZE, hashFunction>::ClearIndex(unsigned int index,const char *file, unsigned int line)
{ {
Node *node = nodeList[index]; Node *node = nodeList[index];
Node *next; Node *next;
while (node) while (node)
{ {
next=node->next; next=node->next;
RakNet::OP_DELETE(node,file,line); RakNet::OP_DELETE(node,file,line);
node=next; node=next;
size--; size--;
} }
nodeList[index]=0; nodeList[index]=0;
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
void Hash<key_type, data_type, HASH_SIZE, hashFunction>::GetAsList(DataStructures::List<data_type> &itemList,DataStructures::List<key_type > &keyList,const char *file, unsigned int line) const void Hash<key_type, data_type, HASH_SIZE, hashFunction>::GetAsList(DataStructures::List<data_type> &itemList,DataStructures::List<key_type > &keyList,const char *file, unsigned int line) const
{ {
if (nodeList==0) if (nodeList==0)
return; return;
itemList.Clear(false,_FILE_AND_LINE_); itemList.Clear(false,_FILE_AND_LINE_);
keyList.Clear(false,_FILE_AND_LINE_); keyList.Clear(false,_FILE_AND_LINE_);
Node *node; Node *node;
unsigned int i; unsigned int i;
for (i=0; i < HASH_SIZE; i++) for (i=0; i < HASH_SIZE; i++)
{ {
if (nodeList[i]) if (nodeList[i])
{ {
node=nodeList[i]; node=nodeList[i];
while (node) while (node)
{ {
itemList.Push(node->data,file,line); itemList.Push(node->data,file,line);
keyList.Push(node->string,file,line); keyList.Push(node->string,file,line);
node=node->next; node=node->next;
} }
} }
} }
} }
template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) > template <class key_type, class data_type, unsigned int HASH_SIZE, unsigned long (*hashFunction)(const key_type &) >
unsigned int Hash<key_type, data_type, HASH_SIZE, hashFunction>::Size(void) const unsigned int Hash<key_type, data_type, HASH_SIZE, hashFunction>::Size(void) const
{ {
return size; return size;
} }
} }
#endif #endif

View File

@@ -1,297 +1,297 @@
/// \file DS_Heap.h /// \file DS_Heap.h
/// \internal /// \internal
/// \brief Heap (Also serves as a priority queue) /// \brief Heap (Also serves as a priority queue)
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __RAKNET_HEAP_H #ifndef __RAKNET_HEAP_H
#define __RAKNET_HEAP_H #define __RAKNET_HEAP_H
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "DS_List.h" #include "DS_List.h"
#include "Export.h" #include "Export.h"
#include "RakAssert.h" #include "RakAssert.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( push ) #pragma warning( push )
#endif #endif
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures namespace DataStructures
{ {
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
class RAK_DLL_EXPORT Heap class RAK_DLL_EXPORT Heap
{ {
public: public:
struct HeapNode struct HeapNode
{ {
HeapNode() {} HeapNode() {}
HeapNode(const weight_type &w, const data_type &d) : weight(w), data(d) {} HeapNode(const weight_type &w, const data_type &d) : weight(w), data(d) {}
weight_type weight; // I'm assuming key is a native numerical type - float or int weight_type weight; // I'm assuming key is a native numerical type - float or int
data_type data; data_type data;
}; };
Heap(); Heap();
~Heap(); ~Heap();
void Push(const weight_type &weight, const data_type &data, const char *file, unsigned int line); void Push(const weight_type &weight, const data_type &data, const char *file, unsigned int line);
/// Call before calling PushSeries, for a new series of items /// Call before calling PushSeries, for a new series of items
void StartSeries(void) {optimizeNextSeriesPush=false;} void StartSeries(void) {optimizeNextSeriesPush=false;}
/// If you are going to push a list of items, where the weights of the items on the list are in order and follow the heap order, PushSeries is faster than Push() /// If you are going to push a list of items, where the weights of the items on the list are in order and follow the heap order, PushSeries is faster than Push()
void PushSeries(const weight_type &weight, const data_type &data, const char *file, unsigned int line); void PushSeries(const weight_type &weight, const data_type &data, const char *file, unsigned int line);
data_type Pop(const unsigned startingIndex); data_type Pop(const unsigned startingIndex);
data_type Peek(const unsigned startingIndex=0) const; data_type Peek(const unsigned startingIndex=0) const;
weight_type PeekWeight(const unsigned startingIndex=0) const; weight_type PeekWeight(const unsigned startingIndex=0) const;
void Clear(bool doNotDeallocateSmallBlocks, const char *file, unsigned int line); void Clear(bool doNotDeallocateSmallBlocks, const char *file, unsigned int line);
data_type& operator[] ( const unsigned int position ) const; data_type& operator[] ( const unsigned int position ) const;
unsigned Size(void) const; unsigned Size(void) const;
protected: protected:
unsigned LeftChild(const unsigned i) const; unsigned LeftChild(const unsigned i) const;
unsigned RightChild(const unsigned i) const; unsigned RightChild(const unsigned i) const;
unsigned Parent(const unsigned i) const; unsigned Parent(const unsigned i) const;
void Swap(const unsigned i, const unsigned j); void Swap(const unsigned i, const unsigned j);
DataStructures::List<HeapNode> heap; DataStructures::List<HeapNode> heap;
bool optimizeNextSeriesPush; bool optimizeNextSeriesPush;
}; };
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
Heap<weight_type, data_type, isMaxHeap>::Heap() Heap<weight_type, data_type, isMaxHeap>::Heap()
{ {
optimizeNextSeriesPush=false; optimizeNextSeriesPush=false;
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
Heap<weight_type, data_type, isMaxHeap>::~Heap() Heap<weight_type, data_type, isMaxHeap>::~Heap()
{ {
//Clear(true, _FILE_AND_LINE_); //Clear(true, _FILE_AND_LINE_);
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
void Heap<weight_type, data_type, isMaxHeap>::PushSeries(const weight_type &weight, const data_type &data, const char *file, unsigned int line) void Heap<weight_type, data_type, isMaxHeap>::PushSeries(const weight_type &weight, const data_type &data, const char *file, unsigned int line)
{ {
if (optimizeNextSeriesPush==false) if (optimizeNextSeriesPush==false)
{ {
// If the weight of what we are inserting is greater than / less than in order of the heap of every sibling and sibling of parent, then can optimize next push // If the weight of what we are inserting is greater than / less than in order of the heap of every sibling and sibling of parent, then can optimize next push
unsigned currentIndex = heap.Size(); unsigned currentIndex = heap.Size();
unsigned parentIndex; unsigned parentIndex;
if (currentIndex>0) if (currentIndex>0)
{ {
for (parentIndex = Parent(currentIndex); parentIndex < currentIndex; parentIndex++) for (parentIndex = Parent(currentIndex); parentIndex < currentIndex; parentIndex++)
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(disable:4127) // conditional expression is constant #pragma warning(disable:4127) // conditional expression is constant
#endif #endif
if (isMaxHeap) if (isMaxHeap)
{ {
// Every child is less than its parent // Every child is less than its parent
if (weight>heap[parentIndex].weight) if (weight>heap[parentIndex].weight)
{ {
// Can't optimize // Can't optimize
Push(weight,data,file,line); Push(weight,data,file,line);
return; return;
} }
} }
else else
{ {
// Every child is greater than than its parent // Every child is greater than than its parent
if (weight<heap[parentIndex].weight) if (weight<heap[parentIndex].weight)
{ {
// Can't optimize // Can't optimize
Push(weight,data,file,line); Push(weight,data,file,line);
return; return;
} }
} }
} }
} }
// Parent's subsequent siblings and this row's siblings all are less than / greater than inserted element. Can insert all further elements straight to the end // Parent's subsequent siblings and this row's siblings all are less than / greater than inserted element. Can insert all further elements straight to the end
heap.Insert(HeapNode(weight, data), file, line); heap.Insert(HeapNode(weight, data), file, line);
optimizeNextSeriesPush=true; optimizeNextSeriesPush=true;
} }
else else
{ {
heap.Insert(HeapNode(weight, data), file, line); heap.Insert(HeapNode(weight, data), file, line);
} }
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
void Heap<weight_type, data_type, isMaxHeap>::Push(const weight_type &weight, const data_type &data, const char *file, unsigned int line) void Heap<weight_type, data_type, isMaxHeap>::Push(const weight_type &weight, const data_type &data, const char *file, unsigned int line)
{ {
unsigned currentIndex = heap.Size(); unsigned currentIndex = heap.Size();
unsigned parentIndex; unsigned parentIndex;
heap.Insert(HeapNode(weight, data), file, line); heap.Insert(HeapNode(weight, data), file, line);
while (currentIndex!=0) while (currentIndex!=0)
{ {
parentIndex = Parent(currentIndex); parentIndex = Parent(currentIndex);
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif #endif
if (isMaxHeap) if (isMaxHeap)
{ {
if (heap[parentIndex].weight < weight) if (heap[parentIndex].weight < weight)
{ {
Swap(currentIndex, parentIndex); Swap(currentIndex, parentIndex);
currentIndex=parentIndex; currentIndex=parentIndex;
} }
else else
break; break;
} }
else else
{ {
if (heap[parentIndex].weight > weight) if (heap[parentIndex].weight > weight)
{ {
Swap(currentIndex, parentIndex); Swap(currentIndex, parentIndex);
currentIndex=parentIndex; currentIndex=parentIndex;
} }
else else
break; break;
} }
} }
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
data_type Heap<weight_type, data_type, isMaxHeap>::Pop(const unsigned startingIndex) data_type Heap<weight_type, data_type, isMaxHeap>::Pop(const unsigned startingIndex)
{ {
// While we have children, swap out with the larger of the two children. // While we have children, swap out with the larger of the two children.
// This line will assert on an empty heap // This line will assert on an empty heap
data_type returnValue=heap[startingIndex].data; data_type returnValue=heap[startingIndex].data;
// Move the last element to the head, and re-heapify // Move the last element to the head, and re-heapify
heap[startingIndex]=heap[heap.Size()-1]; heap[startingIndex]=heap[heap.Size()-1];
unsigned currentIndex,leftChild,rightChild; unsigned currentIndex,leftChild,rightChild;
weight_type currentWeight; weight_type currentWeight;
currentIndex=startingIndex; currentIndex=startingIndex;
currentWeight=heap[startingIndex].weight; currentWeight=heap[startingIndex].weight;
heap.RemoveFromEnd(); heap.RemoveFromEnd();
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif #endif
while (1) while (1)
{ {
leftChild=LeftChild(currentIndex); leftChild=LeftChild(currentIndex);
rightChild=RightChild(currentIndex); rightChild=RightChild(currentIndex);
if (leftChild >= heap.Size()) if (leftChild >= heap.Size())
{ {
// Done // Done
return returnValue; return returnValue;
} }
if (rightChild >= heap.Size()) if (rightChild >= heap.Size())
{ {
// Only left node. // Only left node.
if ((isMaxHeap==true && currentWeight < heap[leftChild].weight) || if ((isMaxHeap==true && currentWeight < heap[leftChild].weight) ||
(isMaxHeap==false && currentWeight > heap[leftChild].weight)) (isMaxHeap==false && currentWeight > heap[leftChild].weight))
Swap(leftChild, currentIndex); Swap(leftChild, currentIndex);
return returnValue; return returnValue;
} }
else else
{ {
// Swap with the bigger/smaller of the two children and continue // Swap with the bigger/smaller of the two children and continue
if (isMaxHeap) if (isMaxHeap)
{ {
if (heap[leftChild].weight <= currentWeight && heap[rightChild].weight <= currentWeight) if (heap[leftChild].weight <= currentWeight && heap[rightChild].weight <= currentWeight)
return returnValue; return returnValue;
if (heap[leftChild].weight > heap[rightChild].weight) if (heap[leftChild].weight > heap[rightChild].weight)
{ {
Swap(leftChild, currentIndex); Swap(leftChild, currentIndex);
currentIndex=leftChild; currentIndex=leftChild;
} }
else else
{ {
Swap(rightChild, currentIndex); Swap(rightChild, currentIndex);
currentIndex=rightChild; currentIndex=rightChild;
} }
} }
else else
{ {
if (heap[leftChild].weight >= currentWeight && heap[rightChild].weight >= currentWeight) if (heap[leftChild].weight >= currentWeight && heap[rightChild].weight >= currentWeight)
return returnValue; return returnValue;
if (heap[leftChild].weight < heap[rightChild].weight) if (heap[leftChild].weight < heap[rightChild].weight)
{ {
Swap(leftChild, currentIndex); Swap(leftChild, currentIndex);
currentIndex=leftChild; currentIndex=leftChild;
} }
else else
{ {
Swap(rightChild, currentIndex); Swap(rightChild, currentIndex);
currentIndex=rightChild; currentIndex=rightChild;
} }
} }
} }
} }
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
inline data_type Heap<weight_type, data_type, isMaxHeap>::Peek(const unsigned startingIndex) const inline data_type Heap<weight_type, data_type, isMaxHeap>::Peek(const unsigned startingIndex) const
{ {
return heap[startingIndex].data; return heap[startingIndex].data;
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
inline weight_type Heap<weight_type, data_type, isMaxHeap>::PeekWeight(const unsigned startingIndex) const inline weight_type Heap<weight_type, data_type, isMaxHeap>::PeekWeight(const unsigned startingIndex) const
{ {
return heap[startingIndex].weight; return heap[startingIndex].weight;
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
void Heap<weight_type, data_type, isMaxHeap>::Clear(bool doNotDeallocateSmallBlocks, const char *file, unsigned int line) void Heap<weight_type, data_type, isMaxHeap>::Clear(bool doNotDeallocateSmallBlocks, const char *file, unsigned int line)
{ {
heap.Clear(doNotDeallocateSmallBlocks, file, line); heap.Clear(doNotDeallocateSmallBlocks, file, line);
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
inline data_type& Heap<weight_type, data_type, isMaxHeap>::operator[] ( const unsigned int position ) const inline data_type& Heap<weight_type, data_type, isMaxHeap>::operator[] ( const unsigned int position ) const
{ {
return heap[position].data; return heap[position].data;
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
unsigned Heap<weight_type, data_type, isMaxHeap>::Size(void) const unsigned Heap<weight_type, data_type, isMaxHeap>::Size(void) const
{ {
return heap.Size(); return heap.Size();
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
inline unsigned Heap<weight_type, data_type, isMaxHeap>::LeftChild(const unsigned i) const inline unsigned Heap<weight_type, data_type, isMaxHeap>::LeftChild(const unsigned i) const
{ {
return i*2+1; return i*2+1;
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
inline unsigned Heap<weight_type, data_type, isMaxHeap>::RightChild(const unsigned i) const inline unsigned Heap<weight_type, data_type, isMaxHeap>::RightChild(const unsigned i) const
{ {
return i*2+2; return i*2+2;
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
inline unsigned Heap<weight_type, data_type, isMaxHeap>::Parent(const unsigned i) const inline unsigned Heap<weight_type, data_type, isMaxHeap>::Parent(const unsigned i) const
{ {
#ifdef _DEBUG #ifdef _DEBUG
RakAssert(i!=0); RakAssert(i!=0);
#endif #endif
return (i-1)/2; return (i-1)/2;
} }
template <class weight_type, class data_type, bool isMaxHeap> template <class weight_type, class data_type, bool isMaxHeap>
void Heap<weight_type, data_type, isMaxHeap>::Swap(const unsigned i, const unsigned j) void Heap<weight_type, data_type, isMaxHeap>::Swap(const unsigned i, const unsigned j)
{ {
HeapNode temp; HeapNode temp;
temp=heap[i]; temp=heap[i];
heap[i]=heap[j]; heap[i]=heap[j];
heap[j]=temp; heap[j]=temp;
} }
} }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( pop ) #pragma warning( pop )
#endif #endif
#endif #endif

View File

@@ -1,299 +1,299 @@
/// \file /// \file
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#include "DS_HuffmanEncodingTree.h" #include "DS_HuffmanEncodingTree.h"
#include "DS_Queue.h" #include "DS_Queue.h"
#include "BitStream.h" #include "BitStream.h"
#include "RakAssert.h" #include "RakAssert.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( push ) #pragma warning( push )
#endif #endif
using namespace RakNet; using namespace RakNet;
HuffmanEncodingTree::HuffmanEncodingTree() HuffmanEncodingTree::HuffmanEncodingTree()
{ {
root = 0; root = 0;
} }
HuffmanEncodingTree::~HuffmanEncodingTree() HuffmanEncodingTree::~HuffmanEncodingTree()
{ {
FreeMemory(); FreeMemory();
} }
void HuffmanEncodingTree::FreeMemory( void ) void HuffmanEncodingTree::FreeMemory( void )
{ {
if ( root == 0 ) if ( root == 0 )
return ; return ;
// Use an in-order traversal to delete the tree // Use an in-order traversal to delete the tree
DataStructures::Queue<HuffmanEncodingTreeNode *> nodeQueue; DataStructures::Queue<HuffmanEncodingTreeNode *> nodeQueue;
HuffmanEncodingTreeNode *node; HuffmanEncodingTreeNode *node;
nodeQueue.Push( root, _FILE_AND_LINE_ ); nodeQueue.Push( root, _FILE_AND_LINE_ );
while ( nodeQueue.Size() > 0 ) while ( nodeQueue.Size() > 0 )
{ {
node = nodeQueue.Pop(); node = nodeQueue.Pop();
if ( node->left ) if ( node->left )
nodeQueue.Push( node->left, _FILE_AND_LINE_ ); nodeQueue.Push( node->left, _FILE_AND_LINE_ );
if ( node->right ) if ( node->right )
nodeQueue.Push( node->right, _FILE_AND_LINE_ ); nodeQueue.Push( node->right, _FILE_AND_LINE_ );
RakNet::OP_DELETE(node, _FILE_AND_LINE_); RakNet::OP_DELETE(node, _FILE_AND_LINE_);
} }
// Delete the encoding table // Delete the encoding table
for ( int i = 0; i < 256; i++ ) for ( int i = 0; i < 256; i++ )
rakFree_Ex(encodingTable[ i ].encoding, _FILE_AND_LINE_ ); rakFree_Ex(encodingTable[ i ].encoding, _FILE_AND_LINE_ );
root = 0; root = 0;
} }
////#include <stdio.h> ////#include <stdio.h>
// Given a frequency table of 256 elements, all with a frequency of 1 or more, generate the tree // Given a frequency table of 256 elements, all with a frequency of 1 or more, generate the tree
void HuffmanEncodingTree::GenerateFromFrequencyTable( unsigned int frequencyTable[ 256 ] ) void HuffmanEncodingTree::GenerateFromFrequencyTable( unsigned int frequencyTable[ 256 ] )
{ {
int counter; int counter;
HuffmanEncodingTreeNode * node; HuffmanEncodingTreeNode * node;
HuffmanEncodingTreeNode *leafList[ 256 ]; // Keep a copy of the pointers to all the leaves so we can generate the encryption table bottom-up, which is easier HuffmanEncodingTreeNode *leafList[ 256 ]; // Keep a copy of the pointers to all the leaves so we can generate the encryption table bottom-up, which is easier
// 1. Make 256 trees each with a weight equal to the frequency of the corresponding character // 1. Make 256 trees each with a weight equal to the frequency of the corresponding character
DataStructures::LinkedList<HuffmanEncodingTreeNode *> huffmanEncodingTreeNodeList; DataStructures::LinkedList<HuffmanEncodingTreeNode *> huffmanEncodingTreeNodeList;
FreeMemory(); FreeMemory();
for ( counter = 0; counter < 256; counter++ ) for ( counter = 0; counter < 256; counter++ )
{ {
node = RakNet::OP_NEW<HuffmanEncodingTreeNode>( _FILE_AND_LINE_ ); node = RakNet::OP_NEW<HuffmanEncodingTreeNode>( _FILE_AND_LINE_ );
node->left = 0; node->left = 0;
node->right = 0; node->right = 0;
node->value = (unsigned char) counter; node->value = (unsigned char) counter;
node->weight = frequencyTable[ counter ]; node->weight = frequencyTable[ counter ];
if ( node->weight == 0 ) if ( node->weight == 0 )
node->weight = 1; // 0 weights are illegal node->weight = 1; // 0 weights are illegal
leafList[ counter ] = node; // Used later to generate the encryption table leafList[ counter ] = node; // Used later to generate the encryption table
InsertNodeIntoSortedList( node, &huffmanEncodingTreeNodeList ); // Insert and maintain sort order. InsertNodeIntoSortedList( node, &huffmanEncodingTreeNodeList ); // Insert and maintain sort order.
} }
// 2. While there is more than one tree, take the two smallest trees and merge them so that the two trees are the left and right // 2. While there is more than one tree, take the two smallest trees and merge them so that the two trees are the left and right
// children of a new node, where the new node has the weight the sum of the weight of the left and right child nodes. // children of a new node, where the new node has the weight the sum of the weight of the left and right child nodes.
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif #endif
while ( 1 ) while ( 1 )
{ {
huffmanEncodingTreeNodeList.Beginning(); huffmanEncodingTreeNodeList.Beginning();
HuffmanEncodingTreeNode *lesser, *greater; HuffmanEncodingTreeNode *lesser, *greater;
lesser = huffmanEncodingTreeNodeList.Pop(); lesser = huffmanEncodingTreeNodeList.Pop();
greater = huffmanEncodingTreeNodeList.Pop(); greater = huffmanEncodingTreeNodeList.Pop();
node = RakNet::OP_NEW<HuffmanEncodingTreeNode>( _FILE_AND_LINE_ ); node = RakNet::OP_NEW<HuffmanEncodingTreeNode>( _FILE_AND_LINE_ );
node->left = lesser; node->left = lesser;
node->right = greater; node->right = greater;
node->weight = lesser->weight + greater->weight; node->weight = lesser->weight + greater->weight;
lesser->parent = node; // This is done to make generating the encryption table easier lesser->parent = node; // This is done to make generating the encryption table easier
greater->parent = node; // This is done to make generating the encryption table easier greater->parent = node; // This is done to make generating the encryption table easier
if ( huffmanEncodingTreeNodeList.Size() == 0 ) if ( huffmanEncodingTreeNodeList.Size() == 0 )
{ {
// 3. Assign the one remaining node in the list to the root node. // 3. Assign the one remaining node in the list to the root node.
root = node; root = node;
root->parent = 0; root->parent = 0;
break; break;
} }
// Put the new node back into the list at the correct spot to maintain the sort. Linear search time // Put the new node back into the list at the correct spot to maintain the sort. Linear search time
InsertNodeIntoSortedList( node, &huffmanEncodingTreeNodeList ); InsertNodeIntoSortedList( node, &huffmanEncodingTreeNodeList );
} }
bool tempPath[ 256 ]; // Maximum path length is 256 bool tempPath[ 256 ]; // Maximum path length is 256
unsigned short tempPathLength; unsigned short tempPathLength;
HuffmanEncodingTreeNode *currentNode; HuffmanEncodingTreeNode *currentNode;
RakNet::BitStream bitStream; RakNet::BitStream bitStream;
// Generate the encryption table. From before, we have an array of pointers to all the leaves which contain pointers to their parents. // Generate the encryption table. From before, we have an array of pointers to all the leaves which contain pointers to their parents.
// This can be done more efficiently but this isn't bad and it's way easier to program and debug // This can be done more efficiently but this isn't bad and it's way easier to program and debug
for ( counter = 0; counter < 256; counter++ ) for ( counter = 0; counter < 256; counter++ )
{ {
// Already done at the end of the loop and before it! // Already done at the end of the loop and before it!
tempPathLength = 0; tempPathLength = 0;
// Set the current node at the leaf // Set the current node at the leaf
currentNode = leafList[ counter ]; currentNode = leafList[ counter ];
do do
{ {
if ( currentNode->parent->left == currentNode ) // We're storing the paths in reverse order.since we are going from the leaf to the root if ( currentNode->parent->left == currentNode ) // We're storing the paths in reverse order.since we are going from the leaf to the root
tempPath[ tempPathLength++ ] = false; tempPath[ tempPathLength++ ] = false;
else else
tempPath[ tempPathLength++ ] = true; tempPath[ tempPathLength++ ] = true;
currentNode = currentNode->parent; currentNode = currentNode->parent;
} }
while ( currentNode != root ); while ( currentNode != root );
// Write to the bitstream in the reverse order that we stored the path, which gives us the correct order from the root to the leaf // Write to the bitstream in the reverse order that we stored the path, which gives us the correct order from the root to the leaf
while ( tempPathLength-- > 0 ) while ( tempPathLength-- > 0 )
{ {
if ( tempPath[ tempPathLength ] ) // Write 1's and 0's because writing a bool will write the BitStream TYPE_CHECKING validation bits if that is defined along with the actual data bit, which is not what we want if ( tempPath[ tempPathLength ] ) // Write 1's and 0's because writing a bool will write the BitStream TYPE_CHECKING validation bits if that is defined along with the actual data bit, which is not what we want
bitStream.Write1(); bitStream.Write1();
else else
bitStream.Write0(); bitStream.Write0();
} }
// Read data from the bitstream, which is written to the encoding table in bits and bitlength. Note this function allocates the encodingTable[counter].encoding pointer // Read data from the bitstream, which is written to the encoding table in bits and bitlength. Note this function allocates the encodingTable[counter].encoding pointer
encodingTable[ counter ].bitLength = ( unsigned char ) bitStream.CopyData( &encodingTable[ counter ].encoding ); encodingTable[ counter ].bitLength = ( unsigned char ) bitStream.CopyData( &encodingTable[ counter ].encoding );
// Reset the bitstream for the next iteration // Reset the bitstream for the next iteration
bitStream.Reset(); bitStream.Reset();
} }
} }
// Pass an array of bytes to array and a preallocated BitStream to receive the output // Pass an array of bytes to array and a preallocated BitStream to receive the output
void HuffmanEncodingTree::EncodeArray( unsigned char *input, size_t sizeInBytes, RakNet::BitStream * output ) void HuffmanEncodingTree::EncodeArray( unsigned char *input, size_t sizeInBytes, RakNet::BitStream * output )
{ {
unsigned counter; unsigned counter;
// For each input byte, Write out the corresponding series of 1's and 0's that give the encoded representation // For each input byte, Write out the corresponding series of 1's and 0's that give the encoded representation
for ( counter = 0; counter < sizeInBytes; counter++ ) for ( counter = 0; counter < sizeInBytes; counter++ )
{ {
output->WriteBits( encodingTable[ input[ counter ] ].encoding, encodingTable[ input[ counter ] ].bitLength, false ); // Data is left aligned output->WriteBits( encodingTable[ input[ counter ] ].encoding, encodingTable[ input[ counter ] ].bitLength, false ); // Data is left aligned
} }
// Byte align the output so the unassigned remaining bits don't equate to some actual value // Byte align the output so the unassigned remaining bits don't equate to some actual value
if ( output->GetNumberOfBitsUsed() % 8 != 0 ) if ( output->GetNumberOfBitsUsed() % 8 != 0 )
{ {
// Find an input that is longer than the remaining bits. Write out part of it to pad the output to be byte aligned. // Find an input that is longer than the remaining bits. Write out part of it to pad the output to be byte aligned.
unsigned char remainingBits = (unsigned char) ( 8 - ( output->GetNumberOfBitsUsed() % 8 ) ); unsigned char remainingBits = (unsigned char) ( 8 - ( output->GetNumberOfBitsUsed() % 8 ) );
for ( counter = 0; counter < 256; counter++ ) for ( counter = 0; counter < 256; counter++ )
if ( encodingTable[ counter ].bitLength > remainingBits ) if ( encodingTable[ counter ].bitLength > remainingBits )
{ {
output->WriteBits( encodingTable[ counter ].encoding, remainingBits, false ); // Data is left aligned output->WriteBits( encodingTable[ counter ].encoding, remainingBits, false ); // Data is left aligned
break; break;
} }
#ifdef _DEBUG #ifdef _DEBUG
RakAssert( counter != 256 ); // Given 256 elements, we should always be able to find an input that would be >= 7 bits RakAssert( counter != 256 ); // Given 256 elements, we should always be able to find an input that would be >= 7 bits
#endif #endif
} }
} }
unsigned HuffmanEncodingTree::DecodeArray( RakNet::BitStream * input, BitSize_t sizeInBits, size_t maxCharsToWrite, unsigned char *output ) unsigned HuffmanEncodingTree::DecodeArray( RakNet::BitStream * input, BitSize_t sizeInBits, size_t maxCharsToWrite, unsigned char *output )
{ {
HuffmanEncodingTreeNode * currentNode; HuffmanEncodingTreeNode * currentNode;
unsigned outputWriteIndex; unsigned outputWriteIndex;
outputWriteIndex = 0; outputWriteIndex = 0;
currentNode = root; currentNode = root;
// For each bit, go left if it is a 0 and right if it is a 1. When we reach a leaf, that gives us the desired value and we restart from the root // For each bit, go left if it is a 0 and right if it is a 1. When we reach a leaf, that gives us the desired value and we restart from the root
for ( unsigned counter = 0; counter < sizeInBits; counter++ ) for ( unsigned counter = 0; counter < sizeInBits; counter++ )
{ {
if ( input->ReadBit() == false ) // left! if ( input->ReadBit() == false ) // left!
currentNode = currentNode->left; currentNode = currentNode->left;
else else
currentNode = currentNode->right; currentNode = currentNode->right;
if ( currentNode->left == 0 && currentNode->right == 0 ) // Leaf if ( currentNode->left == 0 && currentNode->right == 0 ) // Leaf
{ {
if ( outputWriteIndex < maxCharsToWrite ) if ( outputWriteIndex < maxCharsToWrite )
output[ outputWriteIndex ] = currentNode->value; output[ outputWriteIndex ] = currentNode->value;
outputWriteIndex++; outputWriteIndex++;
currentNode = root; currentNode = root;
} }
} }
return outputWriteIndex; return outputWriteIndex;
} }
// Pass an array of encoded bytes to array and a preallocated BitStream to receive the output // Pass an array of encoded bytes to array and a preallocated BitStream to receive the output
void HuffmanEncodingTree::DecodeArray( unsigned char *input, BitSize_t sizeInBits, RakNet::BitStream * output ) void HuffmanEncodingTree::DecodeArray( unsigned char *input, BitSize_t sizeInBits, RakNet::BitStream * output )
{ {
HuffmanEncodingTreeNode * currentNode; HuffmanEncodingTreeNode * currentNode;
if ( sizeInBits <= 0 ) if ( sizeInBits <= 0 )
return ; return ;
RakNet::BitStream bitStream( input, BITS_TO_BYTES(sizeInBits), false ); RakNet::BitStream bitStream( input, BITS_TO_BYTES(sizeInBits), false );
currentNode = root; currentNode = root;
// For each bit, go left if it is a 0 and right if it is a 1. When we reach a leaf, that gives us the desired value and we restart from the root // For each bit, go left if it is a 0 and right if it is a 1. When we reach a leaf, that gives us the desired value and we restart from the root
for ( unsigned counter = 0; counter < sizeInBits; counter++ ) for ( unsigned counter = 0; counter < sizeInBits; counter++ )
{ {
if ( bitStream.ReadBit() == false ) // left! if ( bitStream.ReadBit() == false ) // left!
currentNode = currentNode->left; currentNode = currentNode->left;
else else
currentNode = currentNode->right; currentNode = currentNode->right;
if ( currentNode->left == 0 && currentNode->right == 0 ) // Leaf if ( currentNode->left == 0 && currentNode->right == 0 ) // Leaf
{ {
output->WriteBits( &( currentNode->value ), sizeof( char ) * 8, true ); // Use WriteBits instead of Write(char) because we want to avoid TYPE_CHECKING output->WriteBits( &( currentNode->value ), sizeof( char ) * 8, true ); // Use WriteBits instead of Write(char) because we want to avoid TYPE_CHECKING
currentNode = root; currentNode = root;
} }
} }
} }
// Insertion sort. Slow but easy to write in this case // Insertion sort. Slow but easy to write in this case
void HuffmanEncodingTree::InsertNodeIntoSortedList( HuffmanEncodingTreeNode * node, DataStructures::LinkedList<HuffmanEncodingTreeNode *> *huffmanEncodingTreeNodeList ) const void HuffmanEncodingTree::InsertNodeIntoSortedList( HuffmanEncodingTreeNode * node, DataStructures::LinkedList<HuffmanEncodingTreeNode *> *huffmanEncodingTreeNodeList ) const
{ {
if ( huffmanEncodingTreeNodeList->Size() == 0 ) if ( huffmanEncodingTreeNodeList->Size() == 0 )
{ {
huffmanEncodingTreeNodeList->Insert( node ); huffmanEncodingTreeNodeList->Insert( node );
return ; return ;
} }
huffmanEncodingTreeNodeList->Beginning(); huffmanEncodingTreeNodeList->Beginning();
unsigned counter = 0; unsigned counter = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif #endif
while ( 1 ) while ( 1 )
{ {
if ( huffmanEncodingTreeNodeList->Peek()->weight < node->weight ) if ( huffmanEncodingTreeNodeList->Peek()->weight < node->weight )
++( *huffmanEncodingTreeNodeList ); ++( *huffmanEncodingTreeNodeList );
else else
{ {
huffmanEncodingTreeNodeList->Insert( node ); huffmanEncodingTreeNodeList->Insert( node );
break; break;
} }
// Didn't find a spot in the middle - add to the end // Didn't find a spot in the middle - add to the end
if ( ++counter == huffmanEncodingTreeNodeList->Size() ) if ( ++counter == huffmanEncodingTreeNodeList->Size() )
{ {
huffmanEncodingTreeNodeList->End(); huffmanEncodingTreeNodeList->End();
huffmanEncodingTreeNodeList->Add( node ) huffmanEncodingTreeNodeList->Add( node )
; // Add to the end ; // Add to the end
break; break;
} }
} }
} }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( pop ) #pragma warning( pop )
#endif #endif

View File

@@ -1,67 +1,67 @@
/// \file DS_HuffmanEncodingTree.h /// \file DS_HuffmanEncodingTree.h
/// \brief \b [Internal] Generates a huffman encoding tree, used for string and global compression. /// \brief \b [Internal] Generates a huffman encoding tree, used for string and global compression.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __HUFFMAN_ENCODING_TREE #ifndef __HUFFMAN_ENCODING_TREE
#define __HUFFMAN_ENCODING_TREE #define __HUFFMAN_ENCODING_TREE
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "DS_HuffmanEncodingTreeNode.h" #include "DS_HuffmanEncodingTreeNode.h"
#include "BitStream.h" #include "BitStream.h"
#include "Export.h" #include "Export.h"
#include "DS_LinkedList.h" #include "DS_LinkedList.h"
namespace RakNet namespace RakNet
{ {
/// This generates special cases of the huffman encoding tree using 8 bit keys with the additional condition that unused combinations of 8 bits are treated as a frequency of 1 /// This generates special cases of the huffman encoding tree using 8 bit keys with the additional condition that unused combinations of 8 bits are treated as a frequency of 1
class RAK_DLL_EXPORT HuffmanEncodingTree class RAK_DLL_EXPORT HuffmanEncodingTree
{ {
public: public:
HuffmanEncodingTree(); HuffmanEncodingTree();
~HuffmanEncodingTree(); ~HuffmanEncodingTree();
/// \brief Pass an array of bytes to array and a preallocated BitStream to receive the output. /// \brief Pass an array of bytes to array and a preallocated BitStream to receive the output.
/// \param [in] input Array of bytes to encode /// \param [in] input Array of bytes to encode
/// \param [in] sizeInBytes size of \a input /// \param [in] sizeInBytes size of \a input
/// \param [out] output The bitstream to write to /// \param [out] output The bitstream to write to
void EncodeArray( unsigned char *input, size_t sizeInBytes, RakNet::BitStream * output ); void EncodeArray( unsigned char *input, size_t sizeInBytes, RakNet::BitStream * output );
// \brief Decodes an array encoded by EncodeArray(). // \brief Decodes an array encoded by EncodeArray().
unsigned DecodeArray( RakNet::BitStream * input, BitSize_t sizeInBits, size_t maxCharsToWrite, unsigned char *output ); unsigned DecodeArray( RakNet::BitStream * input, BitSize_t sizeInBits, size_t maxCharsToWrite, unsigned char *output );
void DecodeArray( unsigned char *input, BitSize_t sizeInBits, RakNet::BitStream * output ); void DecodeArray( unsigned char *input, BitSize_t sizeInBits, RakNet::BitStream * output );
/// \brief Given a frequency table of 256 elements, all with a frequency of 1 or more, generate the tree. /// \brief Given a frequency table of 256 elements, all with a frequency of 1 or more, generate the tree.
void GenerateFromFrequencyTable( unsigned int frequencyTable[ 256 ] ); void GenerateFromFrequencyTable( unsigned int frequencyTable[ 256 ] );
/// \brief Free the memory used by the tree. /// \brief Free the memory used by the tree.
void FreeMemory( void ); void FreeMemory( void );
private: private:
/// The root node of the tree /// The root node of the tree
HuffmanEncodingTreeNode *root; HuffmanEncodingTreeNode *root;
/// Used to hold bit encoding for one character /// Used to hold bit encoding for one character
struct CharacterEncoding struct CharacterEncoding
{ {
unsigned char* encoding; unsigned char* encoding;
unsigned short bitLength; unsigned short bitLength;
}; };
CharacterEncoding encodingTable[ 256 ]; CharacterEncoding encodingTable[ 256 ];
void InsertNodeIntoSortedList( HuffmanEncodingTreeNode * node, DataStructures::LinkedList<HuffmanEncodingTreeNode *> *huffmanEncodingTreeNodeList ) const; void InsertNodeIntoSortedList( HuffmanEncodingTreeNode * node, DataStructures::LinkedList<HuffmanEncodingTreeNode *> *huffmanEncodingTreeNodeList ) const;
}; };
} // namespace RakNet } // namespace RakNet
#endif #endif

View File

@@ -1,57 +1,57 @@
/// \file DS_HuffmanEncodingTreeFactory.h /// \file DS_HuffmanEncodingTreeFactory.h
/// \internal /// \internal
/// \brief Creates instances of the class HuffmanEncodingTree /// \brief Creates instances of the class HuffmanEncodingTree
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __HUFFMAN_ENCODING_TREE_FACTORY #ifndef __HUFFMAN_ENCODING_TREE_FACTORY
#define __HUFFMAN_ENCODING_TREE_FACTORY #define __HUFFMAN_ENCODING_TREE_FACTORY
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
namespace RakNet { namespace RakNet {
/// Forward declarations /// Forward declarations
class HuffmanEncodingTree; class HuffmanEncodingTree;
/// \brief Creates instances of the class HuffmanEncodingTree /// \brief Creates instances of the class HuffmanEncodingTree
/// \details This class takes a frequency table and given that frequence table, will generate an instance of HuffmanEncodingTree /// \details This class takes a frequency table and given that frequence table, will generate an instance of HuffmanEncodingTree
class HuffmanEncodingTreeFactory class HuffmanEncodingTreeFactory
{ {
public: public:
/// Default constructor /// Default constructor
HuffmanEncodingTreeFactory(); HuffmanEncodingTreeFactory();
/// \brief Reset the frequency table. /// \brief Reset the frequency table.
/// \details You don't need to call this unless you want to reuse the class for a new tree /// \details You don't need to call this unless you want to reuse the class for a new tree
void Reset( void ); void Reset( void );
/// \brief Pass an array of bytes to this to add those elements to the frequency table. /// \brief Pass an array of bytes to this to add those elements to the frequency table.
/// \param[in] array the data to insert into the frequency table /// \param[in] array the data to insert into the frequency table
/// \param[in] size the size of the data to insert /// \param[in] size the size of the data to insert
void AddToFrequencyTable( unsigned char *array, int size ); void AddToFrequencyTable( unsigned char *array, int size );
/// \brief Copies the frequency table to the array passed. Retrieve the frequency table. /// \brief Copies the frequency table to the array passed. Retrieve the frequency table.
/// \param[in] _frequency The frequency table used currently /// \param[in] _frequency The frequency table used currently
void GetFrequencyTable( unsigned int _frequency[ 256 ] ); void GetFrequencyTable( unsigned int _frequency[ 256 ] );
/// \brief Returns the frequency table as a pointer. /// \brief Returns the frequency table as a pointer.
/// \return the address of the frenquency table /// \return the address of the frenquency table
unsigned int * GetFrequencyTable( void ); unsigned int * GetFrequencyTable( void );
/// \brief Generate a HuffmanEncodingTree. /// \brief Generate a HuffmanEncodingTree.
/// \details You can also use GetFrequencyTable and GenerateFromFrequencyTable in the tree itself /// \details You can also use GetFrequencyTable and GenerateFromFrequencyTable in the tree itself
/// \return The generated instance of HuffmanEncodingTree /// \return The generated instance of HuffmanEncodingTree
HuffmanEncodingTree * GenerateTree( void ); HuffmanEncodingTree * GenerateTree( void );
private: private:
/// Frequency table /// Frequency table
unsigned int frequency[ 256 ]; unsigned int frequency[ 256 ];
}; };
} // namespace RakNet } // namespace RakNet
#endif #endif

View File

@@ -1,21 +1,21 @@
/// \file /// \file
/// \brief \b [Internal] A single node in the Huffman Encoding Tree. /// \brief \b [Internal] A single node in the Huffman Encoding Tree.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __HUFFMAN_ENCODING_TREE_NODE #ifndef __HUFFMAN_ENCODING_TREE_NODE
#define __HUFFMAN_ENCODING_TREE_NODE #define __HUFFMAN_ENCODING_TREE_NODE
struct HuffmanEncodingTreeNode struct HuffmanEncodingTreeNode
{ {
unsigned char value; unsigned char value;
unsigned weight; unsigned weight;
HuffmanEncodingTreeNode *left; HuffmanEncodingTreeNode *left;
HuffmanEncodingTreeNode *right; HuffmanEncodingTreeNode *right;
HuffmanEncodingTreeNode *parent; HuffmanEncodingTreeNode *parent;
}; };
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,321 +1,321 @@
/// \file DS_Map.h /// \file DS_Map.h
/// \internal /// \internal
/// \brief Map /// \brief Map
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __RAKNET_MAP_H #ifndef __RAKNET_MAP_H
#define __RAKNET_MAP_H #define __RAKNET_MAP_H
#include "DS_OrderedList.h" #include "DS_OrderedList.h"
#include "Export.h" #include "Export.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "RakAssert.h" #include "RakAssert.h"
// If I want to change this to a red-black tree, this is a good site: http://www.cs.auckland.ac.nz/software/AlgAnim/red_black.html // If I want to change this to a red-black tree, this is a good site: http://www.cs.auckland.ac.nz/software/AlgAnim/red_black.html
// This makes insertions and deletions faster. But then traversals are slow, while they are currently fast. // This makes insertions and deletions faster. But then traversals are slow, while they are currently fast.
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures namespace DataStructures
{ {
/// The default comparison has to be first so it can be called as a default parameter. /// The default comparison has to be first so it can be called as a default parameter.
/// It then is followed by MapNode, followed by NodeComparisonFunc /// It then is followed by MapNode, followed by NodeComparisonFunc
template <class key_type> template <class key_type>
int defaultMapKeyComparison(const key_type &a, const key_type &b) int defaultMapKeyComparison(const key_type &a, const key_type &b)
{ {
if (a<b) return -1; if (a==b) return 0; return 1; if (a<b) return -1; if (a==b) return 0; return 1;
} }
/// \note IMPORTANT! If you use defaultMapKeyComparison then call IMPLEMENT_DEFAULT_COMPARISON or you will get an unresolved external linker error. /// \note IMPORTANT! If you use defaultMapKeyComparison then call IMPLEMENT_DEFAULT_COMPARISON or you will get an unresolved external linker error.
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&, const key_type&)=defaultMapKeyComparison<key_type> > template <class key_type, class data_type, int (*key_comparison_func)(const key_type&, const key_type&)=defaultMapKeyComparison<key_type> >
class RAK_DLL_EXPORT Map class RAK_DLL_EXPORT Map
{ {
public: public:
static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultMapKeyComparison<key_type>(key_type(),key_type());} static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultMapKeyComparison<key_type>(key_type(),key_type());}
struct MapNode struct MapNode
{ {
MapNode() {} MapNode() {}
MapNode(key_type _key, data_type _data) : mapNodeKey(_key), mapNodeData(_data) {} MapNode(key_type _key, data_type _data) : mapNodeKey(_key), mapNodeData(_data) {}
MapNode& operator = ( const MapNode& input ) {mapNodeKey=input.mapNodeKey; mapNodeData=input.mapNodeData; return *this;} MapNode& operator = ( const MapNode& input ) {mapNodeKey=input.mapNodeKey; mapNodeData=input.mapNodeData; return *this;}
MapNode( const MapNode & input) {mapNodeKey=input.mapNodeKey; mapNodeData=input.mapNodeData;} MapNode( const MapNode & input) {mapNodeKey=input.mapNodeKey; mapNodeData=input.mapNodeData;}
key_type mapNodeKey; key_type mapNodeKey;
data_type mapNodeData; data_type mapNodeData;
}; };
// Has to be a static because the comparison callback for DataStructures::OrderedList is a C function // Has to be a static because the comparison callback for DataStructures::OrderedList is a C function
static int NodeComparisonFunc(const key_type &a, const MapNode &b) static int NodeComparisonFunc(const key_type &a, const MapNode &b)
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif #endif
return key_comparison_func(a, b.mapNodeKey); return key_comparison_func(a, b.mapNodeKey);
} }
Map(); Map();
~Map(); ~Map();
Map( const Map& original_copy ); Map( const Map& original_copy );
Map& operator= ( const Map& original_copy ); Map& operator= ( const Map& original_copy );
data_type& Get(const key_type &key) const; data_type& Get(const key_type &key) const;
data_type Pop(const key_type &key); data_type Pop(const key_type &key);
// Add if needed // Add if needed
void Set(const key_type &key, const data_type &data); void Set(const key_type &key, const data_type &data);
// Must already exist // Must already exist
void SetExisting(const key_type &key, const data_type &data); void SetExisting(const key_type &key, const data_type &data);
// Must add // Must add
void SetNew(const key_type &key, const data_type &data); void SetNew(const key_type &key, const data_type &data);
bool Has(const key_type &key) const; bool Has(const key_type &key) const;
bool Delete(const key_type &key); bool Delete(const key_type &key);
data_type& operator[] ( const unsigned int position ) const; data_type& operator[] ( const unsigned int position ) const;
key_type GetKeyAtIndex( const unsigned int position ) const; key_type GetKeyAtIndex( const unsigned int position ) const;
unsigned GetIndexAtKey( const key_type &key ); unsigned GetIndexAtKey( const key_type &key );
void RemoveAtIndex(const unsigned index); void RemoveAtIndex(const unsigned index);
void Clear(void); void Clear(void);
unsigned Size(void) const; unsigned Size(void) const;
protected: protected:
DataStructures::OrderedList< key_type,MapNode,&Map::NodeComparisonFunc > mapNodeList; DataStructures::OrderedList< key_type,MapNode,&Map::NodeComparisonFunc > mapNodeList;
void SaveLastSearch(const key_type &key, unsigned index) const; void SaveLastSearch(const key_type &key, unsigned index) const;
bool HasSavedSearchResult(const key_type &key) const; bool HasSavedSearchResult(const key_type &key) const;
unsigned lastSearchIndex; unsigned lastSearchIndex;
key_type lastSearchKey; key_type lastSearchKey;
bool lastSearchIndexValid; bool lastSearchIndexValid;
}; };
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
Map<key_type, data_type, key_comparison_func>::Map() Map<key_type, data_type, key_comparison_func>::Map()
{ {
lastSearchIndexValid=false; lastSearchIndexValid=false;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
Map<key_type, data_type, key_comparison_func>::~Map() Map<key_type, data_type, key_comparison_func>::~Map()
{ {
Clear(); Clear();
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
Map<key_type, data_type, key_comparison_func>::Map( const Map& original_copy ) Map<key_type, data_type, key_comparison_func>::Map( const Map& original_copy )
{ {
mapNodeList=original_copy.mapNodeList; mapNodeList=original_copy.mapNodeList;
lastSearchIndex=original_copy.lastSearchIndex; lastSearchIndex=original_copy.lastSearchIndex;
lastSearchKey=original_copy.lastSearchKey; lastSearchKey=original_copy.lastSearchKey;
lastSearchIndexValid=original_copy.lastSearchIndexValid; lastSearchIndexValid=original_copy.lastSearchIndexValid;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
Map<key_type, data_type, key_comparison_func>& Map<key_type, data_type, key_comparison_func>::operator= ( const Map& original_copy ) Map<key_type, data_type, key_comparison_func>& Map<key_type, data_type, key_comparison_func>::operator= ( const Map& original_copy )
{ {
mapNodeList=original_copy.mapNodeList; mapNodeList=original_copy.mapNodeList;
lastSearchIndex=original_copy.lastSearchIndex; lastSearchIndex=original_copy.lastSearchIndex;
lastSearchKey=original_copy.lastSearchKey; lastSearchKey=original_copy.lastSearchKey;
lastSearchIndexValid=original_copy.lastSearchIndexValid; lastSearchIndexValid=original_copy.lastSearchIndexValid;
return *this; return *this;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
data_type& Map<key_type, data_type, key_comparison_func>::Get(const key_type &key) const data_type& Map<key_type, data_type, key_comparison_func>::Get(const key_type &key) const
{ {
if (HasSavedSearchResult(key)) if (HasSavedSearchResult(key))
return mapNodeList[lastSearchIndex].mapNodeData; return mapNodeList[lastSearchIndex].mapNodeData;
bool objectExists; bool objectExists;
unsigned index; unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists); index=mapNodeList.GetIndexFromKey(key, &objectExists);
RakAssert(objectExists); RakAssert(objectExists);
SaveLastSearch(key,index); SaveLastSearch(key,index);
return mapNodeList[index].mapNodeData; return mapNodeList[index].mapNodeData;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
unsigned Map<key_type, data_type, key_comparison_func>::GetIndexAtKey( const key_type &key ) unsigned Map<key_type, data_type, key_comparison_func>::GetIndexAtKey( const key_type &key )
{ {
if (HasSavedSearchResult(key)) if (HasSavedSearchResult(key))
return lastSearchIndex; return lastSearchIndex;
bool objectExists; bool objectExists;
unsigned index; unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists); index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists==false) if (objectExists==false)
{ {
RakAssert(objectExists); RakAssert(objectExists);
} }
SaveLastSearch(key,index); SaveLastSearch(key,index);
return index; return index;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::RemoveAtIndex(const unsigned index) void Map<key_type, data_type, key_comparison_func>::RemoveAtIndex(const unsigned index)
{ {
mapNodeList.RemoveAtIndex(index); mapNodeList.RemoveAtIndex(index);
lastSearchIndexValid=false; lastSearchIndexValid=false;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
data_type Map<key_type, data_type, key_comparison_func>::Pop(const key_type &key) data_type Map<key_type, data_type, key_comparison_func>::Pop(const key_type &key)
{ {
bool objectExists; bool objectExists;
unsigned index; unsigned index;
if (HasSavedSearchResult(key)) if (HasSavedSearchResult(key))
index=lastSearchIndex; index=lastSearchIndex;
else else
{ {
index=mapNodeList.GetIndexFromKey(key, &objectExists); index=mapNodeList.GetIndexFromKey(key, &objectExists);
RakAssert(objectExists); RakAssert(objectExists);
} }
data_type tmp = mapNodeList[index].mapNodeData; data_type tmp = mapNodeList[index].mapNodeData;
mapNodeList.RemoveAtIndex(index); mapNodeList.RemoveAtIndex(index);
lastSearchIndexValid=false; lastSearchIndexValid=false;
return tmp; return tmp;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::Set(const key_type &key, const data_type &data) void Map<key_type, data_type, key_comparison_func>::Set(const key_type &key, const data_type &data)
{ {
bool objectExists; bool objectExists;
unsigned index; unsigned index;
if (HasSavedSearchResult(key)) if (HasSavedSearchResult(key))
{ {
mapNodeList[lastSearchIndex].mapNodeData=data; mapNodeList[lastSearchIndex].mapNodeData=data;
return; return;
} }
index=mapNodeList.GetIndexFromKey(key, &objectExists); index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists) if (objectExists)
{ {
SaveLastSearch(key,index); SaveLastSearch(key,index);
mapNodeList[index].mapNodeData=data; mapNodeList[index].mapNodeData=data;
} }
else else
{ {
SaveLastSearch(key,mapNodeList.Insert(key,MapNode(key,data), true, _FILE_AND_LINE_)); SaveLastSearch(key,mapNodeList.Insert(key,MapNode(key,data), true, _FILE_AND_LINE_));
} }
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::SetExisting(const key_type &key, const data_type &data) void Map<key_type, data_type, key_comparison_func>::SetExisting(const key_type &key, const data_type &data)
{ {
bool objectExists; bool objectExists;
unsigned index; unsigned index;
if (HasSavedSearchResult(key)) if (HasSavedSearchResult(key))
{ {
index=lastSearchIndex; index=lastSearchIndex;
} }
else else
{ {
index=mapNodeList.GetIndexFromKey(key, &objectExists); index=mapNodeList.GetIndexFromKey(key, &objectExists);
RakAssert(objectExists); RakAssert(objectExists);
SaveLastSearch(key,index); SaveLastSearch(key,index);
} }
mapNodeList[index].mapNodeData=data; mapNodeList[index].mapNodeData=data;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::SetNew(const key_type &key, const data_type &data) void Map<key_type, data_type, key_comparison_func>::SetNew(const key_type &key, const data_type &data)
{ {
#ifdef _DEBUG #ifdef _DEBUG
bool objectExists; bool objectExists;
mapNodeList.GetIndexFromKey(key, &objectExists); mapNodeList.GetIndexFromKey(key, &objectExists);
RakAssert(objectExists==false); RakAssert(objectExists==false);
#endif #endif
SaveLastSearch(key,mapNodeList.Insert(key,MapNode(key,data), true, _FILE_AND_LINE_)); SaveLastSearch(key,mapNodeList.Insert(key,MapNode(key,data), true, _FILE_AND_LINE_));
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
bool Map<key_type, data_type, key_comparison_func>::Has(const key_type &key) const bool Map<key_type, data_type, key_comparison_func>::Has(const key_type &key) const
{ {
if (HasSavedSearchResult(key)) if (HasSavedSearchResult(key))
return true; return true;
bool objectExists; bool objectExists;
unsigned index; unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists); index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists) if (objectExists)
SaveLastSearch(key,index); SaveLastSearch(key,index);
return objectExists; return objectExists;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
bool Map<key_type, data_type, key_comparison_func>::Delete(const key_type &key) bool Map<key_type, data_type, key_comparison_func>::Delete(const key_type &key)
{ {
if (HasSavedSearchResult(key)) if (HasSavedSearchResult(key))
{ {
lastSearchIndexValid=false; lastSearchIndexValid=false;
mapNodeList.RemoveAtIndex(lastSearchIndex); mapNodeList.RemoveAtIndex(lastSearchIndex);
return true; return true;
} }
bool objectExists; bool objectExists;
unsigned index; unsigned index;
index=mapNodeList.GetIndexFromKey(key, &objectExists); index=mapNodeList.GetIndexFromKey(key, &objectExists);
if (objectExists) if (objectExists)
{ {
lastSearchIndexValid=false; lastSearchIndexValid=false;
mapNodeList.RemoveAtIndex(index); mapNodeList.RemoveAtIndex(index);
return true; return true;
} }
else else
return false; return false;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::Clear(void) void Map<key_type, data_type, key_comparison_func>::Clear(void)
{ {
lastSearchIndexValid=false; lastSearchIndexValid=false;
mapNodeList.Clear(false, _FILE_AND_LINE_); mapNodeList.Clear(false, _FILE_AND_LINE_);
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
data_type& Map<key_type, data_type, key_comparison_func>::operator[]( const unsigned int position ) const data_type& Map<key_type, data_type, key_comparison_func>::operator[]( const unsigned int position ) const
{ {
return mapNodeList[position].mapNodeData; return mapNodeList[position].mapNodeData;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
key_type Map<key_type, data_type, key_comparison_func>::GetKeyAtIndex( const unsigned int position ) const key_type Map<key_type, data_type, key_comparison_func>::GetKeyAtIndex( const unsigned int position ) const
{ {
return mapNodeList[position].mapNodeKey; return mapNodeList[position].mapNodeKey;
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
unsigned Map<key_type, data_type, key_comparison_func>::Size(void) const unsigned Map<key_type, data_type, key_comparison_func>::Size(void) const
{ {
return mapNodeList.Size(); return mapNodeList.Size();
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
void Map<key_type, data_type, key_comparison_func>::SaveLastSearch(const key_type &key, const unsigned index) const void Map<key_type, data_type, key_comparison_func>::SaveLastSearch(const key_type &key, const unsigned index) const
{ {
(void) key; (void) key;
(void) index; (void) index;
/* /*
lastSearchIndex=index; lastSearchIndex=index;
lastSearchKey=key; lastSearchKey=key;
lastSearchIndexValid=true; lastSearchIndexValid=true;
*/ */
} }
template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)> template <class key_type, class data_type, int (*key_comparison_func)(const key_type&,const key_type&)>
bool Map<key_type, data_type, key_comparison_func>::HasSavedSearchResult(const key_type &key) const bool Map<key_type, data_type, key_comparison_func>::HasSavedSearchResult(const key_type &key) const
{ {
(void) key; (void) key;
// Not threadsafe! // Not threadsafe!
return false; return false;
// return lastSearchIndexValid && key_comparison_func(key,lastSearchKey)==0; // return lastSearchIndexValid && key_comparison_func(key,lastSearchKey)==0;
} }
} }
#endif #endif

View File

@@ -1,294 +1,294 @@
/// \file DS_MemoryPool.h /// \file DS_MemoryPool.h
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __MEMORY_POOL_H #ifndef __MEMORY_POOL_H
#define __MEMORY_POOL_H #define __MEMORY_POOL_H
#ifndef __APPLE__ #ifndef __APPLE__
// Use stdlib and not malloc for compatibility // Use stdlib and not malloc for compatibility
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#include "RakAssert.h" #include "RakAssert.h"
#include "Export.h" #include "Export.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
// DS_MEMORY_POOL_MAX_FREE_PAGES must be > 1 // DS_MEMORY_POOL_MAX_FREE_PAGES must be > 1
#define DS_MEMORY_POOL_MAX_FREE_PAGES 4 #define DS_MEMORY_POOL_MAX_FREE_PAGES 4
//#define _DISABLE_MEMORY_POOL //#define _DISABLE_MEMORY_POOL
namespace DataStructures namespace DataStructures
{ {
/// Very fast memory pool for allocating and deallocating structures that don't have constructors or destructors. /// Very fast memory pool for allocating and deallocating structures that don't have constructors or destructors.
/// Contains a list of pages, each of which has an array of the user structures /// Contains a list of pages, each of which has an array of the user structures
template <class MemoryBlockType> template <class MemoryBlockType>
class RAK_DLL_EXPORT MemoryPool class RAK_DLL_EXPORT MemoryPool
{ {
public: public:
struct Page; struct Page;
struct MemoryWithPage struct MemoryWithPage
{ {
MemoryBlockType userMemory; MemoryBlockType userMemory;
Page *parentPage; Page *parentPage;
}; };
struct Page struct Page
{ {
MemoryWithPage** availableStack; MemoryWithPage** availableStack;
int availableStackSize; int availableStackSize;
MemoryWithPage* block; MemoryWithPage* block;
Page *next, *prev; Page *next, *prev;
}; };
MemoryPool(); MemoryPool();
~MemoryPool(); ~MemoryPool();
void SetPageSize(int size); // Defaults to 16384 bytes void SetPageSize(int size); // Defaults to 16384 bytes
MemoryBlockType *Allocate(const char *file, unsigned int line); MemoryBlockType *Allocate(const char *file, unsigned int line);
void Release(MemoryBlockType *m, const char *file, unsigned int line); void Release(MemoryBlockType *m, const char *file, unsigned int line);
void Clear(const char *file, unsigned int line); void Clear(const char *file, unsigned int line);
int GetAvailablePagesSize(void) const {return availablePagesSize;} int GetAvailablePagesSize(void) const {return availablePagesSize;}
int GetUnavailablePagesSize(void) const {return unavailablePagesSize;} int GetUnavailablePagesSize(void) const {return unavailablePagesSize;}
int GetMemoryPoolPageSize(void) const {return memoryPoolPageSize;} int GetMemoryPoolPageSize(void) const {return memoryPoolPageSize;}
protected: protected:
int BlocksPerPage(void) const; int BlocksPerPage(void) const;
void AllocateFirst(void); void AllocateFirst(void);
bool InitPage(Page *page, Page *prev, const char *file, unsigned int line); bool InitPage(Page *page, Page *prev, const char *file, unsigned int line);
// availablePages contains pages which have room to give the user new blocks. We return these blocks from the head of the list // availablePages contains pages which have room to give the user new blocks. We return these blocks from the head of the list
// unavailablePages are pages which are totally full, and from which we do not return new blocks. // unavailablePages are pages which are totally full, and from which we do not return new blocks.
// Pages move from the head of unavailablePages to the tail of availablePages, and from the head of availablePages to the tail of unavailablePages // Pages move from the head of unavailablePages to the tail of availablePages, and from the head of availablePages to the tail of unavailablePages
Page *availablePages, *unavailablePages; Page *availablePages, *unavailablePages;
int availablePagesSize, unavailablePagesSize; int availablePagesSize, unavailablePagesSize;
int memoryPoolPageSize; int memoryPoolPageSize;
}; };
template<class MemoryBlockType> template<class MemoryBlockType>
MemoryPool<MemoryBlockType>::MemoryPool() MemoryPool<MemoryBlockType>::MemoryPool()
{ {
#ifndef _DISABLE_MEMORY_POOL #ifndef _DISABLE_MEMORY_POOL
//AllocateFirst(); //AllocateFirst();
availablePagesSize=0; availablePagesSize=0;
unavailablePagesSize=0; unavailablePagesSize=0;
memoryPoolPageSize=16384; memoryPoolPageSize=16384;
#endif #endif
} }
template<class MemoryBlockType> template<class MemoryBlockType>
MemoryPool<MemoryBlockType>::~MemoryPool() MemoryPool<MemoryBlockType>::~MemoryPool()
{ {
#ifndef _DISABLE_MEMORY_POOL #ifndef _DISABLE_MEMORY_POOL
Clear(_FILE_AND_LINE_); Clear(_FILE_AND_LINE_);
#endif #endif
} }
template<class MemoryBlockType> template<class MemoryBlockType>
void MemoryPool<MemoryBlockType>::SetPageSize(int size) void MemoryPool<MemoryBlockType>::SetPageSize(int size)
{ {
memoryPoolPageSize=size; memoryPoolPageSize=size;
} }
template<class MemoryBlockType> template<class MemoryBlockType>
MemoryBlockType* MemoryPool<MemoryBlockType>::Allocate(const char *file, unsigned int line) MemoryBlockType* MemoryPool<MemoryBlockType>::Allocate(const char *file, unsigned int line)
{ {
#ifdef _DISABLE_MEMORY_POOL #ifdef _DISABLE_MEMORY_POOL
return (MemoryBlockType*) rakMalloc_Ex(sizeof(MemoryBlockType), file, line); return (MemoryBlockType*) rakMalloc_Ex(sizeof(MemoryBlockType), file, line);
#else #else
if (availablePagesSize>0) if (availablePagesSize>0)
{ {
MemoryBlockType *retVal; MemoryBlockType *retVal;
Page *curPage; Page *curPage;
curPage=availablePages; curPage=availablePages;
retVal = (MemoryBlockType*) curPage->availableStack[--(curPage->availableStackSize)]; retVal = (MemoryBlockType*) curPage->availableStack[--(curPage->availableStackSize)];
if (curPage->availableStackSize==0) if (curPage->availableStackSize==0)
{ {
--availablePagesSize; --availablePagesSize;
availablePages=curPage->next; availablePages=curPage->next;
RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0); RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0);
curPage->next->prev=curPage->prev; curPage->next->prev=curPage->prev;
curPage->prev->next=curPage->next; curPage->prev->next=curPage->next;
if (unavailablePagesSize++==0) if (unavailablePagesSize++==0)
{ {
unavailablePages=curPage; unavailablePages=curPage;
curPage->next=curPage; curPage->next=curPage;
curPage->prev=curPage; curPage->prev=curPage;
} }
else else
{ {
curPage->next=unavailablePages; curPage->next=unavailablePages;
curPage->prev=unavailablePages->prev; curPage->prev=unavailablePages->prev;
unavailablePages->prev->next=curPage; unavailablePages->prev->next=curPage;
unavailablePages->prev=curPage; unavailablePages->prev=curPage;
} }
} }
RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0); RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0);
return retVal; return retVal;
} }
availablePages = (Page *) rakMalloc_Ex(sizeof(Page), file, line); availablePages = (Page *) rakMalloc_Ex(sizeof(Page), file, line);
if (availablePages==0) if (availablePages==0)
return 0; return 0;
availablePagesSize=1; availablePagesSize=1;
if (InitPage(availablePages, availablePages, file, line)==false) if (InitPage(availablePages, availablePages, file, line)==false)
return 0; return 0;
// If this assert hits, we couldn't allocate even 1 block per page. Increase the page size // If this assert hits, we couldn't allocate even 1 block per page. Increase the page size
RakAssert(availablePages->availableStackSize>1); RakAssert(availablePages->availableStackSize>1);
return (MemoryBlockType *) availablePages->availableStack[--availablePages->availableStackSize]; return (MemoryBlockType *) availablePages->availableStack[--availablePages->availableStackSize];
#endif #endif
} }
template<class MemoryBlockType> template<class MemoryBlockType>
void MemoryPool<MemoryBlockType>::Release(MemoryBlockType *m, const char *file, unsigned int line) void MemoryPool<MemoryBlockType>::Release(MemoryBlockType *m, const char *file, unsigned int line)
{ {
#ifdef _DISABLE_MEMORY_POOL #ifdef _DISABLE_MEMORY_POOL
rakFree_Ex(m, file, line); rakFree_Ex(m, file, line);
return; return;
#else #else
// Find the page this block is in and return it. // Find the page this block is in and return it.
Page *curPage; Page *curPage;
MemoryWithPage *memoryWithPage = (MemoryWithPage*)m; MemoryWithPage *memoryWithPage = (MemoryWithPage*)m;
curPage=memoryWithPage->parentPage; curPage=memoryWithPage->parentPage;
if (curPage->availableStackSize==0) if (curPage->availableStackSize==0)
{ {
// The page is in the unavailable list so move it to the available list // The page is in the unavailable list so move it to the available list
curPage->availableStack[curPage->availableStackSize++]=memoryWithPage; curPage->availableStack[curPage->availableStackSize++]=memoryWithPage;
unavailablePagesSize--; unavailablePagesSize--;
// As this page is no longer totally empty, move it to the end of available pages // As this page is no longer totally empty, move it to the end of available pages
curPage->next->prev=curPage->prev; curPage->next->prev=curPage->prev;
curPage->prev->next=curPage->next; curPage->prev->next=curPage->next;
if (unavailablePagesSize>0 && curPage==unavailablePages) if (unavailablePagesSize>0 && curPage==unavailablePages)
unavailablePages=unavailablePages->next; unavailablePages=unavailablePages->next;
if (availablePagesSize++==0) if (availablePagesSize++==0)
{ {
availablePages=curPage; availablePages=curPage;
curPage->next=curPage; curPage->next=curPage;
curPage->prev=curPage; curPage->prev=curPage;
} }
else else
{ {
curPage->next=availablePages; curPage->next=availablePages;
curPage->prev=availablePages->prev; curPage->prev=availablePages->prev;
availablePages->prev->next=curPage; availablePages->prev->next=curPage;
availablePages->prev=curPage; availablePages->prev=curPage;
} }
} }
else else
{ {
curPage->availableStack[curPage->availableStackSize++]=memoryWithPage; curPage->availableStack[curPage->availableStackSize++]=memoryWithPage;
if (curPage->availableStackSize==BlocksPerPage() && if (curPage->availableStackSize==BlocksPerPage() &&
availablePagesSize>=DS_MEMORY_POOL_MAX_FREE_PAGES) availablePagesSize>=DS_MEMORY_POOL_MAX_FREE_PAGES)
{ {
// After a certain point, just deallocate empty pages rather than keep them around // After a certain point, just deallocate empty pages rather than keep them around
if (curPage==availablePages) if (curPage==availablePages)
{ {
availablePages=curPage->next; availablePages=curPage->next;
RakAssert(availablePages->availableStackSize>0); RakAssert(availablePages->availableStackSize>0);
} }
curPage->prev->next=curPage->next; curPage->prev->next=curPage->next;
curPage->next->prev=curPage->prev; curPage->next->prev=curPage->prev;
availablePagesSize--; availablePagesSize--;
rakFree_Ex(curPage->availableStack, file, line ); rakFree_Ex(curPage->availableStack, file, line );
rakFree_Ex(curPage->block, file, line ); rakFree_Ex(curPage->block, file, line );
rakFree_Ex(curPage, file, line ); rakFree_Ex(curPage, file, line );
} }
} }
#endif #endif
} }
template<class MemoryBlockType> template<class MemoryBlockType>
void MemoryPool<MemoryBlockType>::Clear(const char *file, unsigned int line) void MemoryPool<MemoryBlockType>::Clear(const char *file, unsigned int line)
{ {
#ifdef _DISABLE_MEMORY_POOL #ifdef _DISABLE_MEMORY_POOL
return; return;
#else #else
Page *cur, *freed; Page *cur, *freed;
if (availablePagesSize>0) if (availablePagesSize>0)
{ {
cur = availablePages; cur = availablePages;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(disable:4127) // conditional expression is constant #pragma warning(disable:4127) // conditional expression is constant
#endif #endif
while (true) while (true)
// do // do
{ {
rakFree_Ex(cur->availableStack, file, line ); rakFree_Ex(cur->availableStack, file, line );
rakFree_Ex(cur->block, file, line ); rakFree_Ex(cur->block, file, line );
freed=cur; freed=cur;
cur=cur->next; cur=cur->next;
if (cur==availablePages) if (cur==availablePages)
{ {
rakFree_Ex(freed, file, line ); rakFree_Ex(freed, file, line );
break; break;
} }
rakFree_Ex(freed, file, line ); rakFree_Ex(freed, file, line );
}// while(cur!=availablePages); }// while(cur!=availablePages);
} }
if (unavailablePagesSize>0) if (unavailablePagesSize>0)
{ {
cur = unavailablePages; cur = unavailablePages;
while (1) while (1)
//do //do
{ {
rakFree_Ex(cur->availableStack, file, line ); rakFree_Ex(cur->availableStack, file, line );
rakFree_Ex(cur->block, file, line ); rakFree_Ex(cur->block, file, line );
freed=cur; freed=cur;
cur=cur->next; cur=cur->next;
if (cur==unavailablePages) if (cur==unavailablePages)
{ {
rakFree_Ex(freed, file, line ); rakFree_Ex(freed, file, line );
break; break;
} }
rakFree_Ex(freed, file, line ); rakFree_Ex(freed, file, line );
} // while(cur!=unavailablePages); } // while(cur!=unavailablePages);
} }
availablePagesSize=0; availablePagesSize=0;
unavailablePagesSize=0; unavailablePagesSize=0;
#endif #endif
} }
template<class MemoryBlockType> template<class MemoryBlockType>
int MemoryPool<MemoryBlockType>::BlocksPerPage(void) const int MemoryPool<MemoryBlockType>::BlocksPerPage(void) const
{ {
return memoryPoolPageSize / sizeof(MemoryWithPage); return memoryPoolPageSize / sizeof(MemoryWithPage);
} }
template<class MemoryBlockType> template<class MemoryBlockType>
bool MemoryPool<MemoryBlockType>::InitPage(Page *page, Page *prev, const char *file, unsigned int line) bool MemoryPool<MemoryBlockType>::InitPage(Page *page, Page *prev, const char *file, unsigned int line)
{ {
int i=0; int i=0;
const int bpp = BlocksPerPage(); const int bpp = BlocksPerPage();
page->block=(MemoryWithPage*) rakMalloc_Ex(memoryPoolPageSize, file, line); page->block=(MemoryWithPage*) rakMalloc_Ex(memoryPoolPageSize, file, line);
if (page->block==0) if (page->block==0)
return false; return false;
page->availableStack=(MemoryWithPage**)rakMalloc_Ex(sizeof(MemoryWithPage*)*bpp, file, line); page->availableStack=(MemoryWithPage**)rakMalloc_Ex(sizeof(MemoryWithPage*)*bpp, file, line);
if (page->availableStack==0) if (page->availableStack==0)
{ {
rakFree_Ex(page->block, file, line ); rakFree_Ex(page->block, file, line );
return false; return false;
} }
MemoryWithPage *curBlock = page->block; MemoryWithPage *curBlock = page->block;
MemoryWithPage **curStack = page->availableStack; MemoryWithPage **curStack = page->availableStack;
while (i < bpp) while (i < bpp)
{ {
curBlock->parentPage=page; curBlock->parentPage=page;
curStack[i]=curBlock++; curStack[i]=curBlock++;
i++; i++;
} }
page->availableStackSize=bpp; page->availableStackSize=bpp;
page->next=availablePages; page->next=availablePages;
page->prev=prev; page->prev=prev;
return true; return true;
} }
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,244 +1,244 @@
/// \file DS_OrderedChannelHeap.h /// \file DS_OrderedChannelHeap.h
/// \internal /// \internal
/// \brief Ordered Channel Heap . This is a heap where you add to it on multiple ordered channels, with each channel having a different weight. /// \brief Ordered Channel Heap . This is a heap where you add to it on multiple ordered channels, with each channel having a different weight.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __RAKNET_ORDERED_CHANNEL_HEAP_H #ifndef __RAKNET_ORDERED_CHANNEL_HEAP_H
#define __RAKNET_ORDERED_CHANNEL_HEAP_H #define __RAKNET_ORDERED_CHANNEL_HEAP_H
#include "DS_Heap.h" #include "DS_Heap.h"
#include "DS_Map.h" #include "DS_Map.h"
#include "DS_Queue.h" #include "DS_Queue.h"
#include "Export.h" #include "Export.h"
#include "RakAssert.h" #include "RakAssert.h"
#include "Rand.h" #include "Rand.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures namespace DataStructures
{ {
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)=defaultMapKeyComparison<channel_key_type> > template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)=defaultMapKeyComparison<channel_key_type> >
class RAK_DLL_EXPORT OrderedChannelHeap class RAK_DLL_EXPORT OrderedChannelHeap
{ {
public: public:
static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultMapKeyComparison<channel_key_type>(channel_key_type(),channel_key_type());} static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultMapKeyComparison<channel_key_type>(channel_key_type(),channel_key_type());}
OrderedChannelHeap(); OrderedChannelHeap();
~OrderedChannelHeap(); ~OrderedChannelHeap();
void Push(const channel_key_type &channelID, const heap_data_type &data); void Push(const channel_key_type &channelID, const heap_data_type &data);
void PushAtHead(const unsigned index, const channel_key_type &channelID, const heap_data_type &data); void PushAtHead(const unsigned index, const channel_key_type &channelID, const heap_data_type &data);
heap_data_type Pop(const unsigned startingIndex=0); heap_data_type Pop(const unsigned startingIndex=0);
heap_data_type Peek(const unsigned startingIndex) const; heap_data_type Peek(const unsigned startingIndex) const;
void AddChannel(const channel_key_type &channelID, const double weight); void AddChannel(const channel_key_type &channelID, const double weight);
void RemoveChannel(channel_key_type channelID); void RemoveChannel(channel_key_type channelID);
void Clear(void); void Clear(void);
heap_data_type& operator[] ( const unsigned int position ) const; heap_data_type& operator[] ( const unsigned int position ) const;
unsigned ChannelSize(const channel_key_type &channelID); unsigned ChannelSize(const channel_key_type &channelID);
unsigned Size(void) const; unsigned Size(void) const;
struct QueueAndWeight struct QueueAndWeight
{ {
DataStructures::Queue<double> randResultQueue; DataStructures::Queue<double> randResultQueue;
double weight; double weight;
bool signalDeletion; bool signalDeletion;
}; };
struct HeapChannelAndData struct HeapChannelAndData
{ {
HeapChannelAndData() {} HeapChannelAndData() {}
HeapChannelAndData(const channel_key_type &_channel, const heap_data_type &_data) : data(_data), channel(_channel) {} HeapChannelAndData(const channel_key_type &_channel, const heap_data_type &_data) : data(_data), channel(_channel) {}
heap_data_type data; heap_data_type data;
channel_key_type channel; channel_key_type channel;
}; };
protected: protected:
DataStructures::Map<channel_key_type, QueueAndWeight*, channel_key_comparison_func> map; DataStructures::Map<channel_key_type, QueueAndWeight*, channel_key_comparison_func> map;
DataStructures::Heap<double, HeapChannelAndData, true> heap; DataStructures::Heap<double, HeapChannelAndData, true> heap;
void GreatestRandResult(void); void GreatestRandResult(void);
}; };
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::OrderedChannelHeap() OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::OrderedChannelHeap()
{ {
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::~OrderedChannelHeap() OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::~OrderedChannelHeap()
{ {
Clear(); Clear();
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Push(const channel_key_type &channelID, const heap_data_type &data) void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Push(const channel_key_type &channelID, const heap_data_type &data)
{ {
PushAtHead(MAX_UNSIGNED_LONG, channelID, data); PushAtHead(MAX_UNSIGNED_LONG, channelID, data);
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::GreatestRandResult(void) void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::GreatestRandResult(void)
{ {
double greatest; double greatest;
unsigned i; unsigned i;
greatest=0.0; greatest=0.0;
for (i=0; i < map.Size(); i++) for (i=0; i < map.Size(); i++)
{ {
if (map[i]->randResultQueue.Size() && map[i]->randResultQueue[0]>greatest) if (map[i]->randResultQueue.Size() && map[i]->randResultQueue[0]>greatest)
greatest=map[i]->randResultQueue[0]; greatest=map[i]->randResultQueue[0];
} }
return greatest; return greatest;
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::PushAtHead(const unsigned index, const channel_key_type &channelID, const heap_data_type &data) void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::PushAtHead(const unsigned index, const channel_key_type &channelID, const heap_data_type &data)
{ {
// If an assert hits here then this is an unknown channel. Call AddChannel first. // If an assert hits here then this is an unknown channel. Call AddChannel first.
QueueAndWeight *queueAndWeight=map.Get(channelID); QueueAndWeight *queueAndWeight=map.Get(channelID);
double maxRange, minRange, rnd; double maxRange, minRange, rnd;
if (queueAndWeight->randResultQueue.Size()==0) if (queueAndWeight->randResultQueue.Size()==0)
{ {
// Set maxRange to the greatest random number waiting to be returned, rather than 1.0 necessarily // Set maxRange to the greatest random number waiting to be returned, rather than 1.0 necessarily
// This is so weights are scaled similarly among channels. For example, if the head weight for a used channel was .25 // This is so weights are scaled similarly among channels. For example, if the head weight for a used channel was .25
// and then we added another channel, the new channel would need to choose between .25 and 0 // and then we added another channel, the new channel would need to choose between .25 and 0
// If we chose between 1.0 and 0, it would be 1/.25 (4x) more likely to be at the head of the heap than it should be // If we chose between 1.0 and 0, it would be 1/.25 (4x) more likely to be at the head of the heap than it should be
maxRange=GreatestRandResult(); maxRange=GreatestRandResult();
if (maxRange==0.0) if (maxRange==0.0)
maxRange=1.0; maxRange=1.0;
minRange=0.0; minRange=0.0;
} }
else if (index >= queueAndWeight->randResultQueue.Size()) else if (index >= queueAndWeight->randResultQueue.Size())
{ {
maxRange=queueAndWeight->randResultQueue[queueAndWeight->randResultQueue.Size()-1]*.99999999; maxRange=queueAndWeight->randResultQueue[queueAndWeight->randResultQueue.Size()-1]*.99999999;
minRange=0.0; minRange=0.0;
} }
else else
{ {
if (index==0) if (index==0)
{ {
maxRange=GreatestRandResult(); maxRange=GreatestRandResult();
if (maxRange==queueAndWeight->randResultQueue[0]) if (maxRange==queueAndWeight->randResultQueue[0])
maxRange=1.0; maxRange=1.0;
} }
else if (index >= queueAndWeight->randResultQueue.Size()) else if (index >= queueAndWeight->randResultQueue.Size())
maxRange=queueAndWeight->randResultQueue[queueAndWeight->randResultQueue.Size()-1]*.99999999; maxRange=queueAndWeight->randResultQueue[queueAndWeight->randResultQueue.Size()-1]*.99999999;
else else
maxRange=queueAndWeight->randResultQueue[index-1]*.99999999; maxRange=queueAndWeight->randResultQueue[index-1]*.99999999;
minRange=maxRange=queueAndWeight->randResultQueue[index]*1.00000001; minRange=maxRange=queueAndWeight->randResultQueue[index]*1.00000001;
} }
#ifdef _DEBUG #ifdef _DEBUG
RakAssert(maxRange!=0.0); RakAssert(maxRange!=0.0);
#endif #endif
rnd=frandomMT() * (maxRange - minRange); rnd=frandomMT() * (maxRange - minRange);
if (rnd==0.0) if (rnd==0.0)
rnd=maxRange/2.0; rnd=maxRange/2.0;
if (index >= queueAndWeight->randResultQueue.Size()) if (index >= queueAndWeight->randResultQueue.Size())
queueAndWeight->randResultQueue.Push(rnd); queueAndWeight->randResultQueue.Push(rnd);
else else
queueAndWeight->randResultQueue.PushAtHead(rnd, index); queueAndWeight->randResultQueue.PushAtHead(rnd, index);
heap.Push(rnd*queueAndWeight->weight, HeapChannelAndData(channelID, data)); heap.Push(rnd*queueAndWeight->weight, HeapChannelAndData(channelID, data));
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
heap_data_type OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Pop(const unsigned startingIndex) heap_data_type OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Pop(const unsigned startingIndex)
{ {
RakAssert(startingIndex < heap.Size()); RakAssert(startingIndex < heap.Size());
QueueAndWeight *queueAndWeight=map.Get(heap[startingIndex].channel); QueueAndWeight *queueAndWeight=map.Get(heap[startingIndex].channel);
if (startingIndex!=0) if (startingIndex!=0)
{ {
// Ugly - have to count in the heap how many nodes have the same channel, so we know where to delete from in the queue // Ugly - have to count in the heap how many nodes have the same channel, so we know where to delete from in the queue
unsigned indiceCount=0; unsigned indiceCount=0;
unsigned i; unsigned i;
for (i=0; i < startingIndex; i++) for (i=0; i < startingIndex; i++)
if (channel_key_comparison_func(heap[i].channel,heap[startingIndex].channel)==0) if (channel_key_comparison_func(heap[i].channel,heap[startingIndex].channel)==0)
indiceCount++; indiceCount++;
queueAndWeight->randResultQueue.RemoveAtIndex(indiceCount); queueAndWeight->randResultQueue.RemoveAtIndex(indiceCount);
} }
else else
{ {
// TODO - ordered channel heap uses progressively lower values as items are inserted. But this won't give relative ordering among channels. I have to renormalize after every pop. // TODO - ordered channel heap uses progressively lower values as items are inserted. But this won't give relative ordering among channels. I have to renormalize after every pop.
queueAndWeight->randResultQueue.Pop(); queueAndWeight->randResultQueue.Pop();
} }
// Try to remove the channel after every pop, because doing so is not valid while there are elements in the list. // Try to remove the channel after every pop, because doing so is not valid while there are elements in the list.
if (queueAndWeight->signalDeletion) if (queueAndWeight->signalDeletion)
RemoveChannel(heap[startingIndex].channel); RemoveChannel(heap[startingIndex].channel);
return heap.Pop(startingIndex).data; return heap.Pop(startingIndex).data;
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
heap_data_type OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Peek(const unsigned startingIndex) const heap_data_type OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Peek(const unsigned startingIndex) const
{ {
HeapChannelAndData heapChannelAndData = heap.Peek(startingIndex); HeapChannelAndData heapChannelAndData = heap.Peek(startingIndex);
return heapChannelAndData.data; return heapChannelAndData.data;
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::AddChannel(const channel_key_type &channelID, const double weight) void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::AddChannel(const channel_key_type &channelID, const double weight)
{ {
QueueAndWeight *qaw = RakNet::OP_NEW<QueueAndWeight>( _FILE_AND_LINE_ ); QueueAndWeight *qaw = RakNet::OP_NEW<QueueAndWeight>( _FILE_AND_LINE_ );
qaw->weight=weight; qaw->weight=weight;
qaw->signalDeletion=false; qaw->signalDeletion=false;
map.SetNew(channelID, qaw); map.SetNew(channelID, qaw);
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::RemoveChannel(channel_key_type channelID) void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::RemoveChannel(channel_key_type channelID)
{ {
if (map.Has(channelID)) if (map.Has(channelID))
{ {
unsigned i; unsigned i;
i=map.GetIndexAtKey(channelID); i=map.GetIndexAtKey(channelID);
if (map[i]->randResultQueue.Size()==0) if (map[i]->randResultQueue.Size()==0)
{ {
RakNet::OP_DELETE(map[i], _FILE_AND_LINE_); RakNet::OP_DELETE(map[i], _FILE_AND_LINE_);
map.RemoveAtIndex(i); map.RemoveAtIndex(i);
} }
else else
{ {
// Signal this channel for deletion later, because the heap has nodes with this channel right now // Signal this channel for deletion later, because the heap has nodes with this channel right now
map[i]->signalDeletion=true; map[i]->signalDeletion=true;
} }
} }
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
unsigned OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Size(void) const unsigned OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Size(void) const
{ {
return heap.Size(); return heap.Size();
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
heap_data_type& OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::operator[]( const unsigned int position ) const heap_data_type& OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::operator[]( const unsigned int position ) const
{ {
return heap[position].data; return heap[position].data;
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
unsigned OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::ChannelSize(const channel_key_type &channelID) unsigned OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::ChannelSize(const channel_key_type &channelID)
{ {
QueueAndWeight *queueAndWeight=map.Get(channelID); QueueAndWeight *queueAndWeight=map.Get(channelID);
return queueAndWeight->randResultQueue.Size(); return queueAndWeight->randResultQueue.Size();
} }
template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)> template <class channel_key_type, class heap_data_type, int (*channel_key_comparison_func)(const channel_key_type&, const channel_key_type&)>
void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Clear(void) void OrderedChannelHeap<channel_key_type, heap_data_type, channel_key_comparison_func>::Clear(void)
{ {
unsigned i; unsigned i;
for (i=0; i < map.Size(); i++) for (i=0; i < map.Size(); i++)
RakNet::OP_DELETE(map[i], _FILE_AND_LINE_); RakNet::OP_DELETE(map[i], _FILE_AND_LINE_);
map.Clear(_FILE_AND_LINE_); map.Clear(_FILE_AND_LINE_);
heap.Clear(_FILE_AND_LINE_); heap.Clear(_FILE_AND_LINE_);
} }
} }
#endif #endif

View File

@@ -1,263 +1,263 @@
/// \file DS_OrderedList.h /// \file DS_OrderedList.h
/// \internal /// \internal
/// \brief Quicksort ordered list. /// \brief Quicksort ordered list.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#include "DS_List.h" #include "DS_List.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "Export.h" #include "Export.h"
#ifndef __ORDERED_LIST_H #ifndef __ORDERED_LIST_H
#define __ORDERED_LIST_H #define __ORDERED_LIST_H
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures namespace DataStructures
{ {
template <class key_type, class data_type> template <class key_type, class data_type>
int defaultOrderedListComparison(const key_type &a, const data_type &b) int defaultOrderedListComparison(const key_type &a, const data_type &b)
{ {
if (a<b) return -1; if (a==b) return 0; return 1; if (a<b) return -1; if (a==b) return 0; return 1;
} }
/// \note IMPORTANT! If you use defaultOrderedListComparison then call IMPLEMENT_DEFAULT_COMPARISON or you will get an unresolved external linker error. /// \note IMPORTANT! If you use defaultOrderedListComparison then call IMPLEMENT_DEFAULT_COMPARISON or you will get an unresolved external linker error.
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)=defaultOrderedListComparison<key_type, data_type> > template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)=defaultOrderedListComparison<key_type, data_type> >
class RAK_DLL_EXPORT OrderedList class RAK_DLL_EXPORT OrderedList
{ {
public: public:
static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultOrderedListComparison<key_type, data_type>(key_type(),data_type());} static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultOrderedListComparison<key_type, data_type>(key_type(),data_type());}
OrderedList(); OrderedList();
~OrderedList(); ~OrderedList();
OrderedList( const OrderedList& original_copy ); OrderedList( const OrderedList& original_copy );
OrderedList& operator= ( const OrderedList& original_copy ); OrderedList& operator= ( const OrderedList& original_copy );
/// comparisonFunction must take a key_type and a data_type and return <0, ==0, or >0 /// comparisonFunction must take a key_type and a data_type and return <0, ==0, or >0
/// If the data type has comparison operators already defined then you can just use defaultComparison /// If the data type has comparison operators already defined then you can just use defaultComparison
bool HasData(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const; bool HasData(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
// GetIndexFromKey returns where the insert should go at the same time checks if it is there // GetIndexFromKey returns where the insert should go at the same time checks if it is there
unsigned GetIndexFromKey(const key_type &key, bool *objectExists, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const; unsigned GetIndexFromKey(const key_type &key, bool *objectExists, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
data_type GetElementFromKey(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const; data_type GetElementFromKey(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
bool GetElementFromKey(const key_type &key, data_type &element, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const; bool GetElementFromKey(const key_type &key, data_type &element, int (*cf)(const key_type&, const data_type&)=default_comparison_function) const;
unsigned Insert(const key_type &key, const data_type &data, bool assertOnDuplicate, const char *file, unsigned int line, int (*cf)(const key_type&, const data_type&)=default_comparison_function); unsigned Insert(const key_type &key, const data_type &data, bool assertOnDuplicate, const char *file, unsigned int line, int (*cf)(const key_type&, const data_type&)=default_comparison_function);
unsigned Remove(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function); unsigned Remove(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function);
unsigned RemoveIfExists(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function); unsigned RemoveIfExists(const key_type &key, int (*cf)(const key_type&, const data_type&)=default_comparison_function);
data_type& operator[] ( const unsigned int position ) const; data_type& operator[] ( const unsigned int position ) const;
void RemoveAtIndex(const unsigned index); void RemoveAtIndex(const unsigned index);
void InsertAtIndex(const data_type &data, const unsigned index, const char *file, unsigned int line); void InsertAtIndex(const data_type &data, const unsigned index, const char *file, unsigned int line);
void InsertAtEnd(const data_type &data, const char *file, unsigned int line); void InsertAtEnd(const data_type &data, const char *file, unsigned int line);
void RemoveFromEnd(const unsigned num=1); void RemoveFromEnd(const unsigned num=1);
void Clear(bool doNotDeallocate, const char *file, unsigned int line); void Clear(bool doNotDeallocate, const char *file, unsigned int line);
unsigned Size(void) const; unsigned Size(void) const;
protected: protected:
DataStructures::List<data_type> orderedList; DataStructures::List<data_type> orderedList;
}; };
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>::OrderedList() OrderedList<key_type, data_type, default_comparison_function>::OrderedList()
{ {
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>::~OrderedList() OrderedList<key_type, data_type, default_comparison_function>::~OrderedList()
{ {
Clear(false, _FILE_AND_LINE_); Clear(false, _FILE_AND_LINE_);
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>::OrderedList( const OrderedList& original_copy ) OrderedList<key_type, data_type, default_comparison_function>::OrderedList( const OrderedList& original_copy )
{ {
orderedList=original_copy.orderedList; orderedList=original_copy.orderedList;
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
OrderedList<key_type, data_type, default_comparison_function>& OrderedList<key_type, data_type, default_comparison_function>::operator= ( const OrderedList& original_copy ) OrderedList<key_type, data_type, default_comparison_function>& OrderedList<key_type, data_type, default_comparison_function>::operator= ( const OrderedList& original_copy )
{ {
orderedList=original_copy.orderedList; orderedList=original_copy.orderedList;
return *this; return *this;
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
bool OrderedList<key_type, data_type, default_comparison_function>::HasData(const key_type &key, int (*cf)(const key_type&, const data_type&)) const bool OrderedList<key_type, data_type, default_comparison_function>::HasData(const key_type &key, int (*cf)(const key_type&, const data_type&)) const
{ {
bool objectExists; bool objectExists;
GetIndexFromKey(key, &objectExists, cf); GetIndexFromKey(key, &objectExists, cf);
return objectExists; return objectExists;
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
data_type OrderedList<key_type, data_type, default_comparison_function>::GetElementFromKey(const key_type &key, int (*cf)(const key_type&, const data_type&)) const data_type OrderedList<key_type, data_type, default_comparison_function>::GetElementFromKey(const key_type &key, int (*cf)(const key_type&, const data_type&)) const
{ {
bool objectExists; bool objectExists;
unsigned index; unsigned index;
index = GetIndexFromKey(key, &objectExists, cf); index = GetIndexFromKey(key, &objectExists, cf);
RakAssert(objectExists); RakAssert(objectExists);
return orderedList[index]; return orderedList[index];
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
bool OrderedList<key_type, data_type, default_comparison_function>::GetElementFromKey(const key_type &key, data_type &element, int (*cf)(const key_type&, const data_type&)) const bool OrderedList<key_type, data_type, default_comparison_function>::GetElementFromKey(const key_type &key, data_type &element, int (*cf)(const key_type&, const data_type&)) const
{ {
bool objectExists; bool objectExists;
unsigned index; unsigned index;
index = GetIndexFromKey(key, &objectExists, cf); index = GetIndexFromKey(key, &objectExists, cf);
if (objectExists) if (objectExists)
element = orderedList[index]; element = orderedList[index];
return objectExists; return objectExists;
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::GetIndexFromKey(const key_type &key, bool *objectExists, int (*cf)(const key_type&, const data_type&)) const unsigned OrderedList<key_type, data_type, default_comparison_function>::GetIndexFromKey(const key_type &key, bool *objectExists, int (*cf)(const key_type&, const data_type&)) const
{ {
int index, upperBound, lowerBound; int index, upperBound, lowerBound;
int res; int res;
if (orderedList.Size()==0) if (orderedList.Size()==0)
{ {
*objectExists=false; *objectExists=false;
return 0; return 0;
} }
upperBound=(int)orderedList.Size()-1; upperBound=(int)orderedList.Size()-1;
lowerBound=0; lowerBound=0;
index = (int)orderedList.Size()/2; index = (int)orderedList.Size()/2;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif #endif
while (1) while (1)
{ {
res = cf(key,orderedList[index]); res = cf(key,orderedList[index]);
if (res==0) if (res==0)
{ {
*objectExists=true; *objectExists=true;
return index; return index;
} }
else if (res<0) else if (res<0)
{ {
upperBound=index-1; upperBound=index-1;
} }
else// if (res>0) else// if (res>0)
{ {
lowerBound=index+1; lowerBound=index+1;
} }
index=lowerBound+(upperBound-lowerBound)/2; index=lowerBound+(upperBound-lowerBound)/2;
if (lowerBound>upperBound) if (lowerBound>upperBound)
{ {
*objectExists=false; *objectExists=false;
return lowerBound; // No match return lowerBound; // No match
} }
} }
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::Insert(const key_type &key, const data_type &data, bool assertOnDuplicate, const char *file, unsigned int line, int (*cf)(const key_type&, const data_type&)) unsigned OrderedList<key_type, data_type, default_comparison_function>::Insert(const key_type &key, const data_type &data, bool assertOnDuplicate, const char *file, unsigned int line, int (*cf)(const key_type&, const data_type&))
{ {
(void) assertOnDuplicate; (void) assertOnDuplicate;
bool objectExists; bool objectExists;
unsigned index; unsigned index;
index = GetIndexFromKey(key, &objectExists, cf); index = GetIndexFromKey(key, &objectExists, cf);
// Don't allow duplicate insertion. // Don't allow duplicate insertion.
if (objectExists) if (objectExists)
{ {
// This is usually a bug! // This is usually a bug!
RakAssert(assertOnDuplicate==false); RakAssert(assertOnDuplicate==false);
return (unsigned)-1; return (unsigned)-1;
} }
if (index>=orderedList.Size()) if (index>=orderedList.Size())
{ {
orderedList.Insert(data, file, line); orderedList.Insert(data, file, line);
return orderedList.Size()-1; return orderedList.Size()-1;
} }
else else
{ {
orderedList.Insert(data,index, file, line); orderedList.Insert(data,index, file, line);
return index; return index;
} }
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::Remove(const key_type &key, int (*cf)(const key_type&, const data_type&)) unsigned OrderedList<key_type, data_type, default_comparison_function>::Remove(const key_type &key, int (*cf)(const key_type&, const data_type&))
{ {
bool objectExists; bool objectExists;
unsigned index; unsigned index;
index = GetIndexFromKey(key, &objectExists, cf); index = GetIndexFromKey(key, &objectExists, cf);
// Can't find the element to remove if this assert hits // Can't find the element to remove if this assert hits
// RakAssert(objectExists==true); // RakAssert(objectExists==true);
if (objectExists==false) if (objectExists==false)
{ {
RakAssert(objectExists==true); RakAssert(objectExists==true);
return 0; return 0;
} }
orderedList.RemoveAtIndex(index); orderedList.RemoveAtIndex(index);
return index; return index;
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::RemoveIfExists(const key_type &key, int (*cf)(const key_type&, const data_type&)) unsigned OrderedList<key_type, data_type, default_comparison_function>::RemoveIfExists(const key_type &key, int (*cf)(const key_type&, const data_type&))
{ {
bool objectExists; bool objectExists;
unsigned index; unsigned index;
index = GetIndexFromKey(key, &objectExists, cf); index = GetIndexFromKey(key, &objectExists, cf);
// Can't find the element to remove if this assert hits // Can't find the element to remove if this assert hits
if (objectExists==false) if (objectExists==false)
return 0; return 0;
orderedList.RemoveAtIndex(index); orderedList.RemoveAtIndex(index);
return index; return index;
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::RemoveAtIndex(const unsigned index) void OrderedList<key_type, data_type, default_comparison_function>::RemoveAtIndex(const unsigned index)
{ {
orderedList.RemoveAtIndex(index); orderedList.RemoveAtIndex(index);
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::InsertAtIndex(const data_type &data, const unsigned index, const char *file, unsigned int line) void OrderedList<key_type, data_type, default_comparison_function>::InsertAtIndex(const data_type &data, const unsigned index, const char *file, unsigned int line)
{ {
orderedList.Insert(data, index, file, line); orderedList.Insert(data, index, file, line);
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::InsertAtEnd(const data_type &data, const char *file, unsigned int line) void OrderedList<key_type, data_type, default_comparison_function>::InsertAtEnd(const data_type &data, const char *file, unsigned int line)
{ {
orderedList.Insert(data, file, line); orderedList.Insert(data, file, line);
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::RemoveFromEnd(const unsigned num) void OrderedList<key_type, data_type, default_comparison_function>::RemoveFromEnd(const unsigned num)
{ {
orderedList.RemoveFromEnd(num); orderedList.RemoveFromEnd(num);
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
void OrderedList<key_type, data_type, default_comparison_function>::Clear(bool doNotDeallocate, const char *file, unsigned int line) void OrderedList<key_type, data_type, default_comparison_function>::Clear(bool doNotDeallocate, const char *file, unsigned int line)
{ {
orderedList.Clear(doNotDeallocate, file, line); orderedList.Clear(doNotDeallocate, file, line);
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
data_type& OrderedList<key_type, data_type, default_comparison_function>::operator[]( const unsigned int position ) const data_type& OrderedList<key_type, data_type, default_comparison_function>::operator[]( const unsigned int position ) const
{ {
return orderedList[position]; return orderedList[position];
} }
template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)> template <class key_type, class data_type, int (*default_comparison_function)(const key_type&, const data_type&)>
unsigned OrderedList<key_type, data_type, default_comparison_function>::Size(void) const unsigned OrderedList<key_type, data_type, default_comparison_function>::Size(void) const
{ {
return orderedList.Size(); return orderedList.Size();
} }
} }
#endif #endif

View File

@@ -1,435 +1,435 @@
/// \file DS_Queue.h /// \file DS_Queue.h
/// \internal /// \internal
/// \brief A queue used by RakNet. /// \brief A queue used by RakNet.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __QUEUE_H #ifndef __QUEUE_H
#define __QUEUE_H #define __QUEUE_H
// Template classes have to have all the code in the header file // Template classes have to have all the code in the header file
#include "RakAssert.h" #include "RakAssert.h"
#include "Export.h" #include "Export.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures namespace DataStructures
{ {
/// \brief A queue implemented as an array with a read and write index. /// \brief A queue implemented as an array with a read and write index.
template <class queue_type> template <class queue_type>
class RAK_DLL_EXPORT Queue class RAK_DLL_EXPORT Queue
{ {
public: public:
Queue(); Queue();
~Queue(); ~Queue();
Queue( Queue& original_copy ); Queue( Queue& original_copy );
bool operator= ( const Queue& original_copy ); bool operator= ( const Queue& original_copy );
void Push( const queue_type& input, const char *file, unsigned int line ); void Push( const queue_type& input, const char *file, unsigned int line );
void PushAtHead( const queue_type& input, unsigned index, const char *file, unsigned int line ); void PushAtHead( const queue_type& input, unsigned index, const char *file, unsigned int line );
queue_type& operator[] ( unsigned int position ) const; // Not a normal thing you do with a queue but can be used for efficiency queue_type& operator[] ( unsigned int position ) const; // Not a normal thing you do with a queue but can be used for efficiency
void RemoveAtIndex( unsigned int position ); // Not a normal thing you do with a queue but can be used for efficiency void RemoveAtIndex( unsigned int position ); // Not a normal thing you do with a queue but can be used for efficiency
inline queue_type Peek( void ) const; inline queue_type Peek( void ) const;
inline queue_type PeekTail( void ) const; inline queue_type PeekTail( void ) const;
inline queue_type Pop( void ); inline queue_type Pop( void );
// Debug: Set pointer to 0, for memory leak detection // Debug: Set pointer to 0, for memory leak detection
inline queue_type PopDeref( void ); inline queue_type PopDeref( void );
inline unsigned int Size( void ) const; inline unsigned int Size( void ) const;
inline bool IsEmpty(void) const; inline bool IsEmpty(void) const;
inline unsigned int AllocationSize( void ) const; inline unsigned int AllocationSize( void ) const;
inline void Clear( const char *file, unsigned int line ); inline void Clear( const char *file, unsigned int line );
void Compress( const char *file, unsigned int line ); void Compress( const char *file, unsigned int line );
bool Find ( queue_type q ); bool Find ( queue_type q );
void ClearAndForceAllocation( int size, const char *file, unsigned int line ); // Force a memory allocation to a certain larger size void ClearAndForceAllocation( int size, const char *file, unsigned int line ); // Force a memory allocation to a certain larger size
private: private:
queue_type* array; queue_type* array;
unsigned int head; // Array index for the head of the queue unsigned int head; // Array index for the head of the queue
unsigned int tail; // Array index for the tail of the queue unsigned int tail; // Array index for the tail of the queue
unsigned int allocation_size; unsigned int allocation_size;
}; };
template <class queue_type> template <class queue_type>
inline unsigned int Queue<queue_type>::Size( void ) const inline unsigned int Queue<queue_type>::Size( void ) const
{ {
if ( head <= tail ) if ( head <= tail )
return tail -head; return tail -head;
else else
return allocation_size -head + tail; return allocation_size -head + tail;
} }
template <class queue_type> template <class queue_type>
inline bool Queue<queue_type>::IsEmpty(void) const inline bool Queue<queue_type>::IsEmpty(void) const
{ {
return head==tail; return head==tail;
} }
template <class queue_type> template <class queue_type>
inline unsigned int Queue<queue_type>::AllocationSize( void ) const inline unsigned int Queue<queue_type>::AllocationSize( void ) const
{ {
return allocation_size; return allocation_size;
} }
template <class queue_type> template <class queue_type>
Queue<queue_type>::Queue() Queue<queue_type>::Queue()
{ {
//allocation_size = 16; //allocation_size = 16;
//array = RakNet::OP_NEW_ARRAY<queue_type>(allocation_size, _FILE_AND_LINE_ ); //array = RakNet::OP_NEW_ARRAY<queue_type>(allocation_size, _FILE_AND_LINE_ );
allocation_size = 0; allocation_size = 0;
array=0; array=0;
head = 0; head = 0;
tail = 0; tail = 0;
} }
template <class queue_type> template <class queue_type>
Queue<queue_type>::~Queue() Queue<queue_type>::~Queue()
{ {
if (allocation_size>0) if (allocation_size>0)
RakNet::OP_DELETE_ARRAY(array, _FILE_AND_LINE_); RakNet::OP_DELETE_ARRAY(array, _FILE_AND_LINE_);
} }
template <class queue_type> template <class queue_type>
inline queue_type Queue<queue_type>::Pop( void ) inline queue_type Queue<queue_type>::Pop( void )
{ {
#ifdef _DEBUG #ifdef _DEBUG
RakAssert( head != tail); RakAssert( head != tail);
#endif #endif
//head=(head+1) % allocation_size; //head=(head+1) % allocation_size;
if ( ++head == allocation_size ) if ( ++head == allocation_size )
head = 0; head = 0;
if ( head == 0 ) if ( head == 0 )
return ( queue_type ) array[ allocation_size -1 ]; return ( queue_type ) array[ allocation_size -1 ];
return ( queue_type ) array[ head -1 ]; return ( queue_type ) array[ head -1 ];
} }
template <class queue_type> template <class queue_type>
inline queue_type Queue<queue_type>::PopDeref( void ) inline queue_type Queue<queue_type>::PopDeref( void )
{ {
if ( ++head == allocation_size ) if ( ++head == allocation_size )
head = 0; head = 0;
queue_type q; queue_type q;
if ( head == 0 ) if ( head == 0 )
{ {
q=array[ allocation_size -1 ]; q=array[ allocation_size -1 ];
array[ allocation_size -1 ]=0; array[ allocation_size -1 ]=0;
return q; return q;
} }
q=array[ head -1 ]; q=array[ head -1 ];
array[ head -1 ]=0; array[ head -1 ]=0;
return q; return q;
} }
template <class queue_type> template <class queue_type>
void Queue<queue_type>::PushAtHead( const queue_type& input, unsigned index, const char *file, unsigned int line ) void Queue<queue_type>::PushAtHead( const queue_type& input, unsigned index, const char *file, unsigned int line )
{ {
RakAssert(index <= Size()); RakAssert(index <= Size());
// Just force a reallocation, will be overwritten // Just force a reallocation, will be overwritten
Push(input, file, line ); Push(input, file, line );
if (Size()==1) if (Size()==1)
return; return;
unsigned writeIndex, readIndex, trueWriteIndex, trueReadIndex; unsigned writeIndex, readIndex, trueWriteIndex, trueReadIndex;
writeIndex=Size()-1; writeIndex=Size()-1;
readIndex=writeIndex-1; readIndex=writeIndex-1;
while (readIndex >= index) while (readIndex >= index)
{ {
if ( head + writeIndex >= allocation_size ) if ( head + writeIndex >= allocation_size )
trueWriteIndex = head + writeIndex - allocation_size; trueWriteIndex = head + writeIndex - allocation_size;
else else
trueWriteIndex = head + writeIndex; trueWriteIndex = head + writeIndex;
if ( head + readIndex >= allocation_size ) if ( head + readIndex >= allocation_size )
trueReadIndex = head + readIndex - allocation_size; trueReadIndex = head + readIndex - allocation_size;
else else
trueReadIndex = head + readIndex; trueReadIndex = head + readIndex;
array[trueWriteIndex]=array[trueReadIndex]; array[trueWriteIndex]=array[trueReadIndex];
if (readIndex==0) if (readIndex==0)
break; break;
writeIndex--; writeIndex--;
readIndex--; readIndex--;
} }
if ( head + index >= allocation_size ) if ( head + index >= allocation_size )
trueWriteIndex = head + index - allocation_size; trueWriteIndex = head + index - allocation_size;
else else
trueWriteIndex = head + index; trueWriteIndex = head + index;
array[trueWriteIndex]=input; array[trueWriteIndex]=input;
} }
template <class queue_type> template <class queue_type>
inline queue_type Queue<queue_type>::Peek( void ) const inline queue_type Queue<queue_type>::Peek( void ) const
{ {
#ifdef _DEBUG #ifdef _DEBUG
RakAssert( head != tail ); RakAssert( head != tail );
#endif #endif
return ( queue_type ) array[ head ]; return ( queue_type ) array[ head ];
} }
template <class queue_type> template <class queue_type>
inline queue_type Queue<queue_type>::PeekTail( void ) const inline queue_type Queue<queue_type>::PeekTail( void ) const
{ {
#ifdef _DEBUG #ifdef _DEBUG
RakAssert( head != tail ); RakAssert( head != tail );
#endif #endif
if (tail!=0) if (tail!=0)
return ( queue_type ) array[ tail-1 ]; return ( queue_type ) array[ tail-1 ];
else else
return ( queue_type ) array[ allocation_size-1 ]; return ( queue_type ) array[ allocation_size-1 ];
} }
template <class queue_type> template <class queue_type>
void Queue<queue_type>::Push( const queue_type& input, const char *file, unsigned int line ) void Queue<queue_type>::Push( const queue_type& input, const char *file, unsigned int line )
{ {
if ( allocation_size == 0 ) if ( allocation_size == 0 )
{ {
array = RakNet::OP_NEW_ARRAY<queue_type>(16, file, line ); array = RakNet::OP_NEW_ARRAY<queue_type>(16, file, line );
head = 0; head = 0;
tail = 1; tail = 1;
array[ 0 ] = input; array[ 0 ] = input;
allocation_size = 16; allocation_size = 16;
return ; return ;
} }
array[ tail++ ] = input; array[ tail++ ] = input;
if ( tail == allocation_size ) if ( tail == allocation_size )
tail = 0; tail = 0;
if ( tail == head ) if ( tail == head )
{ {
// unsigned int index=tail; // unsigned int index=tail;
// Need to allocate more memory. // Need to allocate more memory.
queue_type * new_array; queue_type * new_array;
new_array = RakNet::OP_NEW_ARRAY<queue_type>(allocation_size * 2, file, line ); new_array = RakNet::OP_NEW_ARRAY<queue_type>(allocation_size * 2, file, line );
#ifdef _DEBUG #ifdef _DEBUG
RakAssert( new_array ); RakAssert( new_array );
#endif #endif
if (new_array==0) if (new_array==0)
return; return;
for ( unsigned int counter = 0; counter < allocation_size; ++counter ) for ( unsigned int counter = 0; counter < allocation_size; ++counter )
new_array[ counter ] = array[ ( head + counter ) % ( allocation_size ) ]; new_array[ counter ] = array[ ( head + counter ) % ( allocation_size ) ];
head = 0; head = 0;
tail = allocation_size; tail = allocation_size;
allocation_size *= 2; allocation_size *= 2;
// Delete the old array and move the pointer to the new array // Delete the old array and move the pointer to the new array
RakNet::OP_DELETE_ARRAY(array, file, line); RakNet::OP_DELETE_ARRAY(array, file, line);
array = new_array; array = new_array;
} }
} }
template <class queue_type> template <class queue_type>
Queue<queue_type>::Queue( Queue& original_copy ) Queue<queue_type>::Queue( Queue& original_copy )
{ {
// Allocate memory for copy // Allocate memory for copy
if ( original_copy.Size() == 0 ) if ( original_copy.Size() == 0 )
{ {
allocation_size = 0; allocation_size = 0;
} }
else else
{ {
array = RakNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 , _FILE_AND_LINE_ ); array = RakNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 , _FILE_AND_LINE_ );
for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter ) for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter )
array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ]; array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ];
head = 0; head = 0;
tail = original_copy.Size(); tail = original_copy.Size();
allocation_size = original_copy.Size() + 1; allocation_size = original_copy.Size() + 1;
} }
} }
template <class queue_type> template <class queue_type>
bool Queue<queue_type>::operator= ( const Queue& original_copy ) bool Queue<queue_type>::operator= ( const Queue& original_copy )
{ {
if ( ( &original_copy ) == this ) if ( ( &original_copy ) == this )
return false; return false;
Clear(_FILE_AND_LINE_); Clear(_FILE_AND_LINE_);
// Allocate memory for copy // Allocate memory for copy
if ( original_copy.Size() == 0 ) if ( original_copy.Size() == 0 )
{ {
allocation_size = 0; allocation_size = 0;
} }
else else
{ {
array = RakNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 , _FILE_AND_LINE_ ); array = RakNet::OP_NEW_ARRAY<queue_type >( original_copy.Size() + 1 , _FILE_AND_LINE_ );
for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter ) for ( unsigned int counter = 0; counter < original_copy.Size(); ++counter )
array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ]; array[ counter ] = original_copy.array[ ( original_copy.head + counter ) % ( original_copy.allocation_size ) ];
head = 0; head = 0;
tail = original_copy.Size(); tail = original_copy.Size();
allocation_size = original_copy.Size() + 1; allocation_size = original_copy.Size() + 1;
} }
return true; return true;
} }
template <class queue_type> template <class queue_type>
inline void Queue<queue_type>::Clear ( const char *file, unsigned int line ) inline void Queue<queue_type>::Clear ( const char *file, unsigned int line )
{ {
if ( allocation_size == 0 ) if ( allocation_size == 0 )
return ; return ;
if (allocation_size > 32) if (allocation_size > 32)
{ {
RakNet::OP_DELETE_ARRAY(array, file, line); RakNet::OP_DELETE_ARRAY(array, file, line);
allocation_size = 0; allocation_size = 0;
} }
head = 0; head = 0;
tail = 0; tail = 0;
} }
template <class queue_type> template <class queue_type>
void Queue<queue_type>::Compress ( const char *file, unsigned int line ) void Queue<queue_type>::Compress ( const char *file, unsigned int line )
{ {
queue_type* new_array; queue_type* new_array;
unsigned int newAllocationSize; unsigned int newAllocationSize;
if (allocation_size==0) if (allocation_size==0)
return; return;
newAllocationSize=1; newAllocationSize=1;
while (newAllocationSize <= Size()) while (newAllocationSize <= Size())
newAllocationSize<<=1; // Must be a better way to do this but I'm too dumb to figure it out quickly :) newAllocationSize<<=1; // Must be a better way to do this but I'm too dumb to figure it out quickly :)
new_array = RakNet::OP_NEW_ARRAY<queue_type >(newAllocationSize, file, line ); new_array = RakNet::OP_NEW_ARRAY<queue_type >(newAllocationSize, file, line );
for (unsigned int counter=0; counter < Size(); ++counter) for (unsigned int counter=0; counter < Size(); ++counter)
new_array[counter] = array[(head + counter)%(allocation_size)]; new_array[counter] = array[(head + counter)%(allocation_size)];
tail=Size(); tail=Size();
allocation_size=newAllocationSize; allocation_size=newAllocationSize;
head=0; head=0;
// Delete the old array and move the pointer to the new array // Delete the old array and move the pointer to the new array
RakNet::OP_DELETE_ARRAY(array, file, line); RakNet::OP_DELETE_ARRAY(array, file, line);
array=new_array; array=new_array;
} }
template <class queue_type> template <class queue_type>
bool Queue<queue_type>::Find ( queue_type q ) bool Queue<queue_type>::Find ( queue_type q )
{ {
if ( allocation_size == 0 ) if ( allocation_size == 0 )
return false; return false;
unsigned int counter = head; unsigned int counter = head;
while ( counter != tail ) while ( counter != tail )
{ {
if ( array[ counter ] == q ) if ( array[ counter ] == q )
return true; return true;
counter = ( counter + 1 ) % allocation_size; counter = ( counter + 1 ) % allocation_size;
} }
return false; return false;
} }
template <class queue_type> template <class queue_type>
void Queue<queue_type>::ClearAndForceAllocation( int size, const char *file, unsigned int line ) void Queue<queue_type>::ClearAndForceAllocation( int size, const char *file, unsigned int line )
{ {
RakNet::OP_DELETE_ARRAY(array, file, line); RakNet::OP_DELETE_ARRAY(array, file, line);
if (size>0) if (size>0)
array = RakNet::OP_NEW_ARRAY<queue_type>(size, file, line ); array = RakNet::OP_NEW_ARRAY<queue_type>(size, file, line );
else else
array=0; array=0;
allocation_size = size; allocation_size = size;
head = 0; head = 0;
tail = 0; tail = 0;
} }
template <class queue_type> template <class queue_type>
inline queue_type& Queue<queue_type>::operator[] ( unsigned int position ) const inline queue_type& Queue<queue_type>::operator[] ( unsigned int position ) const
{ {
#ifdef _DEBUG #ifdef _DEBUG
RakAssert( position < Size() ); RakAssert( position < Size() );
#endif #endif
//return array[(head + position) % allocation_size]; //return array[(head + position) % allocation_size];
if ( head + position >= allocation_size ) if ( head + position >= allocation_size )
return array[ head + position - allocation_size ]; return array[ head + position - allocation_size ];
else else
return array[ head + position ]; return array[ head + position ];
} }
template <class queue_type> template <class queue_type>
void Queue<queue_type>::RemoveAtIndex( unsigned int position ) void Queue<queue_type>::RemoveAtIndex( unsigned int position )
{ {
#ifdef _DEBUG #ifdef _DEBUG
RakAssert( position < Size() ); RakAssert( position < Size() );
RakAssert( head != tail ); RakAssert( head != tail );
#endif #endif
if ( head == tail || position >= Size() ) if ( head == tail || position >= Size() )
return ; return ;
unsigned int index; unsigned int index;
unsigned int next; unsigned int next;
//index = (head + position) % allocation_size; //index = (head + position) % allocation_size;
if ( head + position >= allocation_size ) if ( head + position >= allocation_size )
index = head + position - allocation_size; index = head + position - allocation_size;
else else
index = head + position; index = head + position;
//next = (index + 1) % allocation_size; //next = (index + 1) % allocation_size;
next = index + 1; next = index + 1;
if ( next == allocation_size ) if ( next == allocation_size )
next = 0; next = 0;
while ( next != tail ) while ( next != tail )
{ {
// Overwrite the previous element // Overwrite the previous element
array[ index ] = array[ next ]; array[ index ] = array[ next ];
index = next; index = next;
//next = (next + 1) % allocation_size; //next = (next + 1) % allocation_size;
if ( ++next == allocation_size ) if ( ++next == allocation_size )
next = 0; next = 0;
} }
// Move the tail back // Move the tail back
if ( tail == 0 ) if ( tail == 0 )
tail = allocation_size - 1; tail = allocation_size - 1;
else else
--tail; --tail;
} }
} // End namespace } // End namespace
#endif #endif

View File

@@ -1,103 +1,103 @@
/// \file DS_QueueLinkedList.h /// \file DS_QueueLinkedList.h
/// \internal /// \internal
/// \brief A queue implemented as a linked list. /// \brief A queue implemented as a linked list.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __QUEUE_LINKED_LIST_H #ifndef __QUEUE_LINKED_LIST_H
#define __QUEUE_LINKED_LIST_H #define __QUEUE_LINKED_LIST_H
#include "DS_LinkedList.h" #include "DS_LinkedList.h"
#include "Export.h" #include "Export.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures namespace DataStructures
{ {
/// \brief A queue implemented using a linked list. Rarely used. /// \brief A queue implemented using a linked list. Rarely used.
template <class QueueType> template <class QueueType>
class RAK_DLL_EXPORT QueueLinkedList class RAK_DLL_EXPORT QueueLinkedList
{ {
public: public:
QueueLinkedList(); QueueLinkedList();
QueueLinkedList( const QueueLinkedList& original_copy ); QueueLinkedList( const QueueLinkedList& original_copy );
bool operator= ( const QueueLinkedList& original_copy ); bool operator= ( const QueueLinkedList& original_copy );
QueueType Pop( void ); QueueType Pop( void );
QueueType& Peek( void ); QueueType& Peek( void );
QueueType& EndPeek( void ); QueueType& EndPeek( void );
void Push( const QueueType& input ); void Push( const QueueType& input );
unsigned int Size( void ); unsigned int Size( void );
void Clear( void ); void Clear( void );
void Compress( void ); void Compress( void );
private: private:
LinkedList<QueueType> data; LinkedList<QueueType> data;
}; };
template <class QueueType> template <class QueueType>
QueueLinkedList<QueueType>::QueueLinkedList() QueueLinkedList<QueueType>::QueueLinkedList()
{ {
} }
template <class QueueType> template <class QueueType>
inline unsigned int QueueLinkedList<QueueType>::Size() inline unsigned int QueueLinkedList<QueueType>::Size()
{ {
return data.Size(); return data.Size();
} }
template <class QueueType> template <class QueueType>
inline QueueType QueueLinkedList<QueueType>::Pop( void ) inline QueueType QueueLinkedList<QueueType>::Pop( void )
{ {
data.Beginning(); data.Beginning();
return ( QueueType ) data.Pop(); return ( QueueType ) data.Pop();
} }
template <class QueueType> template <class QueueType>
inline QueueType& QueueLinkedList<QueueType>::Peek( void ) inline QueueType& QueueLinkedList<QueueType>::Peek( void )
{ {
data.Beginning(); data.Beginning();
return ( QueueType ) data.Peek(); return ( QueueType ) data.Peek();
} }
template <class QueueType> template <class QueueType>
inline QueueType& QueueLinkedList<QueueType>::EndPeek( void ) inline QueueType& QueueLinkedList<QueueType>::EndPeek( void )
{ {
data.End(); data.End();
return ( QueueType ) data.Peek(); return ( QueueType ) data.Peek();
} }
template <class QueueType> template <class QueueType>
void QueueLinkedList<QueueType>::Push( const QueueType& input ) void QueueLinkedList<QueueType>::Push( const QueueType& input )
{ {
data.End(); data.End();
data.Add( input ); data.Add( input );
} }
template <class QueueType> template <class QueueType>
QueueLinkedList<QueueType>::QueueLinkedList( const QueueLinkedList& original_copy ) QueueLinkedList<QueueType>::QueueLinkedList( const QueueLinkedList& original_copy )
{ {
data = original_copy.data; data = original_copy.data;
} }
template <class QueueType> template <class QueueType>
bool QueueLinkedList<QueueType>::operator= ( const QueueLinkedList& original_copy ) bool QueueLinkedList<QueueType>::operator= ( const QueueLinkedList& original_copy )
{ {
if ( ( &original_copy ) == this ) if ( ( &original_copy ) == this )
return false; return false;
data = original_copy.data; data = original_copy.data;
} }
template <class QueueType> template <class QueueType>
void QueueLinkedList<QueueType>::Clear ( void ) void QueueLinkedList<QueueType>::Clear ( void )
{ {
data.Clear(); data.Clear();
} }
} // End namespace } // End namespace
#endif #endif

View File

@@ -1,236 +1,236 @@
/// \file DS_RangeList.h /// \file DS_RangeList.h
/// \internal /// \internal
/// \brief A queue implemented as a linked list. /// \brief A queue implemented as a linked list.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __RANGE_LIST_H #ifndef __RANGE_LIST_H
#define __RANGE_LIST_H #define __RANGE_LIST_H
#include "DS_OrderedList.h" #include "DS_OrderedList.h"
#include "BitStream.h" #include "BitStream.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "RakAssert.h" #include "RakAssert.h"
namespace DataStructures namespace DataStructures
{ {
template <class range_type> template <class range_type>
struct RangeNode struct RangeNode
{ {
RangeNode() {} RangeNode() {}
~RangeNode() {} ~RangeNode() {}
RangeNode(range_type min, range_type max) {minIndex=min; maxIndex=max;} RangeNode(range_type min, range_type max) {minIndex=min; maxIndex=max;}
range_type minIndex; range_type minIndex;
range_type maxIndex; range_type maxIndex;
}; };
template <class range_type> template <class range_type>
int RangeNodeComp(const range_type &a, const RangeNode<range_type> &b) int RangeNodeComp(const range_type &a, const RangeNode<range_type> &b)
{ {
if (a<b.minIndex) if (a<b.minIndex)
return -1; return -1;
if (a==b.minIndex) if (a==b.minIndex)
return 0; return 0;
return 1; return 1;
} }
template <class range_type> template <class range_type>
class RAK_DLL_EXPORT RangeList class RAK_DLL_EXPORT RangeList
{ {
public: public:
RangeList(); RangeList();
~RangeList(); ~RangeList();
void Insert(range_type index); void Insert(range_type index);
void Clear(void); void Clear(void);
unsigned Size(void) const; unsigned Size(void) const;
unsigned RangeSum(void) const; unsigned RangeSum(void) const;
RakNet::BitSize_t Serialize(RakNet::BitStream *in, RakNet::BitSize_t maxBits, bool clearSerialized); RakNet::BitSize_t Serialize(RakNet::BitStream *in, RakNet::BitSize_t maxBits, bool clearSerialized);
bool Deserialize(RakNet::BitStream *out); bool Deserialize(RakNet::BitStream *out);
DataStructures::OrderedList<range_type, RangeNode<range_type> , RangeNodeComp<range_type> > ranges; DataStructures::OrderedList<range_type, RangeNode<range_type> , RangeNodeComp<range_type> > ranges;
}; };
template <class range_type> template <class range_type>
RakNet::BitSize_t RangeList<range_type>::Serialize(RakNet::BitStream *in, RakNet::BitSize_t maxBits, bool clearSerialized) RakNet::BitSize_t RangeList<range_type>::Serialize(RakNet::BitStream *in, RakNet::BitSize_t maxBits, bool clearSerialized)
{ {
RakAssert(ranges.Size() < (unsigned short)-1); RakAssert(ranges.Size() < (unsigned short)-1);
RakNet::BitStream tempBS; RakNet::BitStream tempBS;
RakNet::BitSize_t bitsWritten; RakNet::BitSize_t bitsWritten;
unsigned short countWritten; unsigned short countWritten;
unsigned i; unsigned i;
countWritten=0; countWritten=0;
bitsWritten=0; bitsWritten=0;
for (i=0; i < ranges.Size(); i++) for (i=0; i < ranges.Size(); i++)
{ {
if ((int)sizeof(unsigned short)*8+bitsWritten+(int)sizeof(range_type)*8*2+1>maxBits) if ((int)sizeof(unsigned short)*8+bitsWritten+(int)sizeof(range_type)*8*2+1>maxBits)
break; break;
unsigned char minEqualsMax; unsigned char minEqualsMax;
if (ranges[i].minIndex==ranges[i].maxIndex) if (ranges[i].minIndex==ranges[i].maxIndex)
minEqualsMax=1; minEqualsMax=1;
else else
minEqualsMax=0; minEqualsMax=0;
tempBS.Write(minEqualsMax); // Use one byte, intead of one bit, for speed, as this is done a lot tempBS.Write(minEqualsMax); // Use one byte, intead of one bit, for speed, as this is done a lot
tempBS.Write(ranges[i].minIndex); tempBS.Write(ranges[i].minIndex);
bitsWritten+=sizeof(range_type)*8+8; bitsWritten+=sizeof(range_type)*8+8;
if (ranges[i].minIndex!=ranges[i].maxIndex) if (ranges[i].minIndex!=ranges[i].maxIndex)
{ {
tempBS.Write(ranges[i].maxIndex); tempBS.Write(ranges[i].maxIndex);
bitsWritten+=sizeof(range_type)*8; bitsWritten+=sizeof(range_type)*8;
} }
countWritten++; countWritten++;
} }
in->AlignWriteToByteBoundary(); in->AlignWriteToByteBoundary();
RakNet::BitSize_t before=in->GetWriteOffset(); RakNet::BitSize_t before=in->GetWriteOffset();
in->Write(countWritten); in->Write(countWritten);
bitsWritten+=in->GetWriteOffset()-before; bitsWritten+=in->GetWriteOffset()-before;
// RAKNET_DEBUG_PRINTF("%i ", in->GetNumberOfBitsUsed()); // RAKNET_DEBUG_PRINTF("%i ", in->GetNumberOfBitsUsed());
in->Write(&tempBS, tempBS.GetNumberOfBitsUsed()); in->Write(&tempBS, tempBS.GetNumberOfBitsUsed());
// RAKNET_DEBUG_PRINTF("%i %i \n", tempBS.GetNumberOfBitsUsed(),in->GetNumberOfBitsUsed()); // RAKNET_DEBUG_PRINTF("%i %i \n", tempBS.GetNumberOfBitsUsed(),in->GetNumberOfBitsUsed());
if (clearSerialized && countWritten) if (clearSerialized && countWritten)
{ {
unsigned rangeSize=ranges.Size(); unsigned rangeSize=ranges.Size();
for (i=0; i < rangeSize-countWritten; i++) for (i=0; i < rangeSize-countWritten; i++)
{ {
ranges[i]=ranges[i+countWritten]; ranges[i]=ranges[i+countWritten];
} }
ranges.RemoveFromEnd(countWritten); ranges.RemoveFromEnd(countWritten);
} }
return bitsWritten; return bitsWritten;
} }
template <class range_type> template <class range_type>
bool RangeList<range_type>::Deserialize(RakNet::BitStream *out) bool RangeList<range_type>::Deserialize(RakNet::BitStream *out)
{ {
ranges.Clear(true, _FILE_AND_LINE_); ranges.Clear(true, _FILE_AND_LINE_);
unsigned short count; unsigned short count;
out->AlignReadToByteBoundary(); out->AlignReadToByteBoundary();
out->Read(count); out->Read(count);
unsigned short i; unsigned short i;
range_type min,max; range_type min,max;
unsigned char maxEqualToMin=0; unsigned char maxEqualToMin=0;
for (i=0; i < count; i++) for (i=0; i < count; i++)
{ {
out->Read(maxEqualToMin); out->Read(maxEqualToMin);
if (out->Read(min)==false) if (out->Read(min)==false)
return false; return false;
if (maxEqualToMin==false) if (maxEqualToMin==false)
{ {
if (out->Read(max)==false) if (out->Read(max)==false)
return false; return false;
if (max<min) if (max<min)
return false; return false;
} }
else else
max=min; max=min;
ranges.InsertAtEnd(RangeNode<range_type>(min,max), _FILE_AND_LINE_); ranges.InsertAtEnd(RangeNode<range_type>(min,max), _FILE_AND_LINE_);
} }
return true; return true;
} }
template <class range_type> template <class range_type>
RangeList<range_type>::RangeList() RangeList<range_type>::RangeList()
{ {
RangeNodeComp<range_type>(0, RangeNode<range_type>()); RangeNodeComp<range_type>(0, RangeNode<range_type>());
} }
template <class range_type> template <class range_type>
RangeList<range_type>::~RangeList() RangeList<range_type>::~RangeList()
{ {
Clear(); Clear();
} }
template <class range_type> template <class range_type>
void RangeList<range_type>::Insert(range_type index) void RangeList<range_type>::Insert(range_type index)
{ {
if (ranges.Size()==0) if (ranges.Size()==0)
{ {
ranges.Insert(index, RangeNode<range_type>(index, index), true, _FILE_AND_LINE_); ranges.Insert(index, RangeNode<range_type>(index, index), true, _FILE_AND_LINE_);
return; return;
} }
bool objectExists; bool objectExists;
unsigned insertionIndex=ranges.GetIndexFromKey(index, &objectExists); unsigned insertionIndex=ranges.GetIndexFromKey(index, &objectExists);
if (insertionIndex==ranges.Size()) if (insertionIndex==ranges.Size())
{ {
if (index == ranges[insertionIndex-1].maxIndex+(range_type)1) if (index == ranges[insertionIndex-1].maxIndex+(range_type)1)
ranges[insertionIndex-1].maxIndex++; ranges[insertionIndex-1].maxIndex++;
else if (index > ranges[insertionIndex-1].maxIndex+(range_type)1) else if (index > ranges[insertionIndex-1].maxIndex+(range_type)1)
{ {
// Insert at end // Insert at end
ranges.Insert(index, RangeNode<range_type>(index, index), true, _FILE_AND_LINE_); ranges.Insert(index, RangeNode<range_type>(index, index), true, _FILE_AND_LINE_);
} }
return; return;
} }
if (index < ranges[insertionIndex].minIndex-(range_type)1) if (index < ranges[insertionIndex].minIndex-(range_type)1)
{ {
// Insert here // Insert here
ranges.InsertAtIndex(RangeNode<range_type>(index, index), insertionIndex, _FILE_AND_LINE_); ranges.InsertAtIndex(RangeNode<range_type>(index, index), insertionIndex, _FILE_AND_LINE_);
return; return;
} }
else if (index == ranges[insertionIndex].minIndex-(range_type)1) else if (index == ranges[insertionIndex].minIndex-(range_type)1)
{ {
// Decrease minIndex and join left // Decrease minIndex and join left
ranges[insertionIndex].minIndex--; ranges[insertionIndex].minIndex--;
if (insertionIndex>0 && ranges[insertionIndex-1].maxIndex+(range_type)1==ranges[insertionIndex].minIndex) if (insertionIndex>0 && ranges[insertionIndex-1].maxIndex+(range_type)1==ranges[insertionIndex].minIndex)
{ {
ranges[insertionIndex-1].maxIndex=ranges[insertionIndex].maxIndex; ranges[insertionIndex-1].maxIndex=ranges[insertionIndex].maxIndex;
ranges.RemoveAtIndex(insertionIndex); ranges.RemoveAtIndex(insertionIndex);
} }
return; return;
} }
else if (index >= ranges[insertionIndex].minIndex && index <= ranges[insertionIndex].maxIndex) else if (index >= ranges[insertionIndex].minIndex && index <= ranges[insertionIndex].maxIndex)
{ {
// Already exists // Already exists
return; return;
} }
else if (index == ranges[insertionIndex].maxIndex+(range_type)1) else if (index == ranges[insertionIndex].maxIndex+(range_type)1)
{ {
// Increase maxIndex and join right // Increase maxIndex and join right
ranges[insertionIndex].maxIndex++; ranges[insertionIndex].maxIndex++;
if (insertionIndex<ranges.Size()-1 && ranges[insertionIndex+(range_type)1].minIndex==ranges[insertionIndex].maxIndex+(range_type)1) if (insertionIndex<ranges.Size()-1 && ranges[insertionIndex+(range_type)1].minIndex==ranges[insertionIndex].maxIndex+(range_type)1)
{ {
ranges[insertionIndex+1].minIndex=ranges[insertionIndex].minIndex; ranges[insertionIndex+1].minIndex=ranges[insertionIndex].minIndex;
ranges.RemoveAtIndex(insertionIndex); ranges.RemoveAtIndex(insertionIndex);
} }
return; return;
} }
} }
template <class range_type> template <class range_type>
void RangeList<range_type>::Clear(void) void RangeList<range_type>::Clear(void)
{ {
ranges.Clear(true, _FILE_AND_LINE_); ranges.Clear(true, _FILE_AND_LINE_);
} }
template <class range_type> template <class range_type>
unsigned RangeList<range_type>::Size(void) const unsigned RangeList<range_type>::Size(void) const
{ {
return ranges.Size(); return ranges.Size();
} }
template <class range_type> template <class range_type>
unsigned RangeList<range_type>::RangeSum(void) const unsigned RangeList<range_type>::RangeSum(void) const
{ {
unsigned sum=0,i; unsigned sum=0,i;
for (i=0; i < ranges.Size(); i++) for (i=0; i < ranges.Size(); i++)
sum+=ranges[i].maxIndex-ranges[i].minIndex+1; sum+=ranges[i].maxIndex-ranges[i].minIndex+1;
return sum; return sum;
} }
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,343 +1,343 @@
/// \file DS_Table.h /// \file DS_Table.h
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __TABLE_H #ifndef __TABLE_H
#define __TABLE_H #define __TABLE_H
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( push ) #pragma warning( push )
#endif #endif
#include "DS_List.h" #include "DS_List.h"
#include "DS_BPlusTree.h" #include "DS_BPlusTree.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "Export.h" #include "Export.h"
#include "RakString.h" #include "RakString.h"
#define _TABLE_BPLUS_TREE_ORDER 16 #define _TABLE_BPLUS_TREE_ORDER 16
#define _TABLE_MAX_COLUMN_NAME_LENGTH 64 #define _TABLE_MAX_COLUMN_NAME_LENGTH 64
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures namespace DataStructures
{ {
/// \brief Holds a set of columns, a set of rows, and rows times columns cells. /// \brief Holds a set of columns, a set of rows, and rows times columns cells.
/// \details The table data structure is useful if you want to store a set of structures and perform queries on those structures.<BR> /// \details The table data structure is useful if you want to store a set of structures and perform queries on those structures.<BR>
/// This is a relatively simple and fast implementation of the types of tables commonly used in databases.<BR> /// This is a relatively simple and fast implementation of the types of tables commonly used in databases.<BR>
/// See TableSerializer to serialize data members of the table.<BR> /// See TableSerializer to serialize data members of the table.<BR>
/// See LightweightDatabaseClient and LightweightDatabaseServer to transmit the table over the network. /// See LightweightDatabaseClient and LightweightDatabaseServer to transmit the table over the network.
class RAK_DLL_EXPORT Table class RAK_DLL_EXPORT Table
{ {
public: public:
enum ColumnType enum ColumnType
{ {
// Cell::i used // Cell::i used
NUMERIC, NUMERIC,
// Cell::c used to hold a null terminated string. // Cell::c used to hold a null terminated string.
STRING, STRING,
// Cell::c holds data. Cell::i holds data length of c in bytes. // Cell::c holds data. Cell::i holds data length of c in bytes.
BINARY, BINARY,
// Cell::c holds data. Not deallocated. Set manually by assigning ptr. // Cell::c holds data. Not deallocated. Set manually by assigning ptr.
POINTER, POINTER,
}; };
/// Holds the actual data in the table /// Holds the actual data in the table
// Note: If this structure is changed the struct in the swig files need to be changed as well // Note: If this structure is changed the struct in the swig files need to be changed as well
struct RAK_DLL_EXPORT Cell struct RAK_DLL_EXPORT Cell
{ {
Cell(); Cell();
~Cell(); ~Cell();
Cell(double numericValue, char *charValue, void *ptr, ColumnType type); Cell(double numericValue, char *charValue, void *ptr, ColumnType type);
void SetByType(double numericValue, char *charValue, void *ptr, ColumnType type); void SetByType(double numericValue, char *charValue, void *ptr, ColumnType type);
void Clear(void); void Clear(void);
/// Numeric /// Numeric
void Set(int input); void Set(int input);
void Set(unsigned int input); void Set(unsigned int input);
void Set(double input); void Set(double input);
/// String /// String
void Set(const char *input); void Set(const char *input);
/// Binary /// Binary
void Set(const char *input, int inputLength); void Set(const char *input, int inputLength);
/// Pointer /// Pointer
void SetPtr(void* p); void SetPtr(void* p);
/// Numeric /// Numeric
void Get(int *output); void Get(int *output);
void Get(double *output); void Get(double *output);
/// String /// String
void Get(char *output); void Get(char *output);
/// Binary /// Binary
void Get(char *output, int *outputLength); void Get(char *output, int *outputLength);
RakNet::RakString ToString(ColumnType columnType); RakNet::RakString ToString(ColumnType columnType);
// assignment operator and copy constructor // assignment operator and copy constructor
Cell& operator = ( const Cell& input ); Cell& operator = ( const Cell& input );
Cell( const Cell & input); Cell( const Cell & input);
ColumnType EstimateColumnType(void) const; ColumnType EstimateColumnType(void) const;
bool isEmpty; bool isEmpty;
double i; double i;
char *c; char *c;
void *ptr; void *ptr;
}; };
/// Stores the name and type of the column /// Stores the name and type of the column
/// \internal /// \internal
// Note: If this structure is changed the struct in the swig files need to be changed as well // Note: If this structure is changed the struct in the swig files need to be changed as well
struct RAK_DLL_EXPORT ColumnDescriptor struct RAK_DLL_EXPORT ColumnDescriptor
{ {
ColumnDescriptor(); ColumnDescriptor();
~ColumnDescriptor(); ~ColumnDescriptor();
ColumnDescriptor(const char cn[_TABLE_MAX_COLUMN_NAME_LENGTH],ColumnType ct); ColumnDescriptor(const char cn[_TABLE_MAX_COLUMN_NAME_LENGTH],ColumnType ct);
char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]; char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH];
ColumnType columnType; ColumnType columnType;
}; };
/// Stores the list of cells for this row, and a special flag used for internal sorting /// Stores the list of cells for this row, and a special flag used for internal sorting
// Note: If this structure is changed the struct in the swig files need to be changed as well // Note: If this structure is changed the struct in the swig files need to be changed as well
struct RAK_DLL_EXPORT Row struct RAK_DLL_EXPORT Row
{ {
// list of cells // list of cells
DataStructures::List<Cell*> cells; DataStructures::List<Cell*> cells;
/// Numeric /// Numeric
void UpdateCell(unsigned columnIndex, double value); void UpdateCell(unsigned columnIndex, double value);
/// String /// String
void UpdateCell(unsigned columnIndex, const char *str); void UpdateCell(unsigned columnIndex, const char *str);
/// Binary /// Binary
void UpdateCell(unsigned columnIndex, int byteLength, const char *data); void UpdateCell(unsigned columnIndex, int byteLength, const char *data);
}; };
// Operations to perform for cell comparison // Operations to perform for cell comparison
enum FilterQueryType enum FilterQueryType
{ {
QF_EQUAL, QF_EQUAL,
QF_NOT_EQUAL, QF_NOT_EQUAL,
QF_GREATER_THAN, QF_GREATER_THAN,
QF_GREATER_THAN_EQ, QF_GREATER_THAN_EQ,
QF_LESS_THAN, QF_LESS_THAN,
QF_LESS_THAN_EQ, QF_LESS_THAN_EQ,
QF_IS_EMPTY, QF_IS_EMPTY,
QF_NOT_EMPTY, QF_NOT_EMPTY,
}; };
// Compare the cell value for a row at columnName to the cellValue using operation. // Compare the cell value for a row at columnName to the cellValue using operation.
// Note: If this structure is changed the struct in the swig files need to be changed as well // Note: If this structure is changed the struct in the swig files need to be changed as well
struct RAK_DLL_EXPORT FilterQuery struct RAK_DLL_EXPORT FilterQuery
{ {
FilterQuery(); FilterQuery();
~FilterQuery(); ~FilterQuery();
FilterQuery(unsigned column, Cell *cell, FilterQueryType op); FilterQuery(unsigned column, Cell *cell, FilterQueryType op);
// If columnName is specified, columnIndex will be looked up using it. // If columnName is specified, columnIndex will be looked up using it.
char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]; char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH];
unsigned columnIndex; unsigned columnIndex;
Cell *cellValue; Cell *cellValue;
FilterQueryType operation; FilterQueryType operation;
}; };
/// Increasing or decreasing sort order /// Increasing or decreasing sort order
enum SortQueryType enum SortQueryType
{ {
QS_INCREASING_ORDER, QS_INCREASING_ORDER,
QS_DECREASING_ORDER, QS_DECREASING_ORDER,
}; };
// Sort on increasing or decreasing order for a particular column // Sort on increasing or decreasing order for a particular column
// Note: If this structure is changed the struct in the swig files need to be changed as well // Note: If this structure is changed the struct in the swig files need to be changed as well
struct RAK_DLL_EXPORT SortQuery struct RAK_DLL_EXPORT SortQuery
{ {
/// The index of the table column we are sorting on /// The index of the table column we are sorting on
unsigned columnIndex; unsigned columnIndex;
/// See SortQueryType /// See SortQueryType
SortQueryType operation; SortQueryType operation;
}; };
// Constructor // Constructor
Table(); Table();
// Destructor // Destructor
~Table(); ~Table();
/// \brief Adds a column to the table /// \brief Adds a column to the table
/// \param[in] columnName The name of the column /// \param[in] columnName The name of the column
/// \param[in] columnType What type of data this column will hold /// \param[in] columnType What type of data this column will hold
/// \return The index of the new column /// \return The index of the new column
unsigned AddColumn(const char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH], ColumnType columnType); unsigned AddColumn(const char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH], ColumnType columnType);
/// \brief Removes a column by index /// \brief Removes a column by index
/// \param[in] columnIndex The index of the column to remove /// \param[in] columnIndex The index of the column to remove
void RemoveColumn(unsigned columnIndex); void RemoveColumn(unsigned columnIndex);
/// \brief Gets the index of a column by name /// \brief Gets the index of a column by name
/// \details Column indices are stored in the order they are added. /// \details Column indices are stored in the order they are added.
/// \param[in] columnName The name of the column /// \param[in] columnName The name of the column
/// \return The index of the column, or (unsigned)-1 if no such column /// \return The index of the column, or (unsigned)-1 if no such column
unsigned ColumnIndex(char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]) const; unsigned ColumnIndex(char columnName[_TABLE_MAX_COLUMN_NAME_LENGTH]) const;
unsigned ColumnIndex(const char *columnName) const; unsigned ColumnIndex(const char *columnName) const;
/// \brief Gives the string name of the column at a certain index /// \brief Gives the string name of the column at a certain index
/// \param[in] index The index of the column /// \param[in] index The index of the column
/// \return The name of the column, or 0 if an invalid index /// \return The name of the column, or 0 if an invalid index
char* ColumnName(unsigned index) const; char* ColumnName(unsigned index) const;
/// \brief Returns the type of a column, referenced by index /// \brief Returns the type of a column, referenced by index
/// \param[in] index The index of the column /// \param[in] index The index of the column
/// \return The type of the column /// \return The type of the column
ColumnType GetColumnType(unsigned index) const; ColumnType GetColumnType(unsigned index) const;
/// Returns the number of columns /// Returns the number of columns
/// \return The number of columns in the table /// \return The number of columns in the table
unsigned GetColumnCount(void) const; unsigned GetColumnCount(void) const;
/// Returns the number of rows /// Returns the number of rows
/// \return The number of rows in the table /// \return The number of rows in the table
unsigned GetRowCount(void) const; unsigned GetRowCount(void) const;
/// \brief Adds a row to the table /// \brief Adds a row to the table
/// \details New rows are added with empty values for all cells. However, if you specify initialCelLValues you can specify initial values /// \details New rows are added with empty values for all cells. However, if you specify initialCelLValues you can specify initial values
/// It's up to you to ensure that the values in the specific cells match the type of data used by that row /// It's up to you to ensure that the values in the specific cells match the type of data used by that row
/// rowId can be considered the primary key for the row. It is much faster to lookup a row by its rowId than by searching keys. /// rowId can be considered the primary key for the row. It is much faster to lookup a row by its rowId than by searching keys.
/// rowId must be unique /// rowId must be unique
/// Rows are stored in sorted order in the table, using rowId as the sort key /// Rows are stored in sorted order in the table, using rowId as the sort key
/// \param[in] rowId The UNIQUE primary key for the row. This can never be changed. /// \param[in] rowId The UNIQUE primary key for the row. This can never be changed.
/// \param[in] initialCellValues Initial values to give the row (optional) /// \param[in] initialCellValues Initial values to give the row (optional)
/// \return The newly added row /// \return The newly added row
Table::Row* AddRow(unsigned rowId); Table::Row* AddRow(unsigned rowId);
Table::Row* AddRow(unsigned rowId, DataStructures::List<Cell> &initialCellValues); Table::Row* AddRow(unsigned rowId, DataStructures::List<Cell> &initialCellValues);
Table::Row* AddRow(unsigned rowId, DataStructures::List<Cell*> &initialCellValues, bool copyCells=false); Table::Row* AddRow(unsigned rowId, DataStructures::List<Cell*> &initialCellValues, bool copyCells=false);
/// \brief Removes a row specified by rowId. /// \brief Removes a row specified by rowId.
/// \param[in] rowId The ID of the row /// \param[in] rowId The ID of the row
/// \return true if the row was deleted. False if not. /// \return true if the row was deleted. False if not.
bool RemoveRow(unsigned rowId); bool RemoveRow(unsigned rowId);
/// \brief Removes all the rows with IDs that the specified table also has. /// \brief Removes all the rows with IDs that the specified table also has.
/// \param[in] tableContainingRowIDs The IDs of the rows /// \param[in] tableContainingRowIDs The IDs of the rows
void RemoveRows(Table *tableContainingRowIDs); void RemoveRows(Table *tableContainingRowIDs);
/// \brief Updates a particular cell in the table. /// \brief Updates a particular cell in the table.
/// \note If you are going to update many cells of a particular row, it is more efficient to call GetRow and perform the operations on the row directly. /// \note If you are going to update many cells of a particular row, it is more efficient to call GetRow and perform the operations on the row directly.
/// \note Row pointers do not change, so you can also write directly to the rows for more efficiency. /// \note Row pointers do not change, so you can also write directly to the rows for more efficiency.
/// \param[in] rowId The ID of the row /// \param[in] rowId The ID of the row
/// \param[in] columnIndex The column of the cell /// \param[in] columnIndex The column of the cell
/// \param[in] value The data to set /// \param[in] value The data to set
bool UpdateCell(unsigned rowId, unsigned columnIndex, int value); bool UpdateCell(unsigned rowId, unsigned columnIndex, int value);
bool UpdateCell(unsigned rowId, unsigned columnIndex, char *str); bool UpdateCell(unsigned rowId, unsigned columnIndex, char *str);
bool UpdateCell(unsigned rowId, unsigned columnIndex, int byteLength, char *data); bool UpdateCell(unsigned rowId, unsigned columnIndex, int byteLength, char *data);
bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int value); bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int value);
bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, char *str); bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, char *str);
bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int byteLength, char *data); bool UpdateCellByIndex(unsigned rowIndex, unsigned columnIndex, int byteLength, char *data);
/// \brief Note this is much less efficient to call than GetRow, then working with the cells directly. /// \brief Note this is much less efficient to call than GetRow, then working with the cells directly.
/// Numeric, string, binary /// Numeric, string, binary
void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, int *output); void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, int *output);
void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output); void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output);
void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output, int *outputLength); void GetCellValueByIndex(unsigned rowIndex, unsigned columnIndex, char *output, int *outputLength);
/// \brief Gets a row. More efficient to do this and access Row::cells than to repeatedly call GetCell. /// \brief Gets a row. More efficient to do this and access Row::cells than to repeatedly call GetCell.
/// You can also update cells in rows from this function. /// You can also update cells in rows from this function.
/// \param[in] rowId The ID of the row /// \param[in] rowId The ID of the row
/// \return The desired row, or 0 if no such row. /// \return The desired row, or 0 if no such row.
Row* GetRowByID(unsigned rowId) const; Row* GetRowByID(unsigned rowId) const;
/// \brief Gets a row at a specific index. /// \brief Gets a row at a specific index.
/// rowIndex should be less than GetRowCount() /// rowIndex should be less than GetRowCount()
/// \param[in] rowIndex The index of the row /// \param[in] rowIndex The index of the row
/// \param[out] key The ID of the row returned /// \param[out] key The ID of the row returned
/// \return The desired row, or 0 if no such row. /// \return The desired row, or 0 if no such row.
Row* GetRowByIndex(unsigned rowIndex, unsigned *key) const; Row* GetRowByIndex(unsigned rowIndex, unsigned *key) const;
/// \brief Queries the table, optionally returning only a subset of columns and rows. /// \brief Queries the table, optionally returning only a subset of columns and rows.
/// \param[in] columnSubset An array of column indices. Only columns in this array are returned. Pass 0 for all columns /// \param[in] columnSubset An array of column indices. Only columns in this array are returned. Pass 0 for all columns
/// \param[in] numColumnSubset The number of elements in \a columnSubset /// \param[in] numColumnSubset The number of elements in \a columnSubset
/// \param[in] inclusionFilters An array of FilterQuery. All filters must pass for the row to be returned. /// \param[in] inclusionFilters An array of FilterQuery. All filters must pass for the row to be returned.
/// \param[in] numInclusionFilters The number of elements in \a inclusionFilters /// \param[in] numInclusionFilters The number of elements in \a inclusionFilters
/// \param[in] rowIds An arrow of row IDs. Only these rows with these IDs are returned. Pass 0 for all rows. /// \param[in] rowIds An arrow of row IDs. Only these rows with these IDs are returned. Pass 0 for all rows.
/// \param[in] numRowIDs The number of elements in \a rowIds /// \param[in] numRowIDs The number of elements in \a rowIds
/// \param[out] result The result of the query. If no rows are returned, the table will only have columns. /// \param[out] result The result of the query. If no rows are returned, the table will only have columns.
void QueryTable(unsigned *columnIndicesSubset, unsigned numColumnSubset, FilterQuery *inclusionFilters, unsigned numInclusionFilters, unsigned *rowIds, unsigned numRowIDs, Table *result); void QueryTable(unsigned *columnIndicesSubset, unsigned numColumnSubset, FilterQuery *inclusionFilters, unsigned numInclusionFilters, unsigned *rowIds, unsigned numRowIDs, Table *result);
/// \brief Sorts the table by rows /// \brief Sorts the table by rows
/// \details You can sort the table in ascending or descending order on one or more columns /// \details You can sort the table in ascending or descending order on one or more columns
/// Columns have precedence in the order they appear in the \a sortQueries array /// Columns have precedence in the order they appear in the \a sortQueries array
/// If a row cell on column n has the same value as a a different row on column n, then the row will be compared on column n+1 /// If a row cell on column n has the same value as a a different row on column n, then the row will be compared on column n+1
/// \param[in] sortQueries A list of SortQuery structures, defining the sorts to perform on the table /// \param[in] sortQueries A list of SortQuery structures, defining the sorts to perform on the table
/// \param[in] numColumnSubset The number of elements in \a numSortQueries /// \param[in] numColumnSubset The number of elements in \a numSortQueries
/// \param[out] out The address of an array of Rows, which will receive the sorted output. The array must be long enough to contain all returned rows, up to GetRowCount() /// \param[out] out The address of an array of Rows, which will receive the sorted output. The array must be long enough to contain all returned rows, up to GetRowCount()
void SortTable(Table::SortQuery *sortQueries, unsigned numSortQueries, Table::Row** out); void SortTable(Table::SortQuery *sortQueries, unsigned numSortQueries, Table::Row** out);
/// \brief Frees all memory in the table. /// \brief Frees all memory in the table.
void Clear(void); void Clear(void);
/// \brief Prints out the names of all the columns. /// \brief Prints out the names of all the columns.
/// \param[out] out A pointer to an array of bytes which will hold the output. /// \param[out] out A pointer to an array of bytes which will hold the output.
/// \param[in] outLength The size of the \a out array /// \param[in] outLength The size of the \a out array
/// \param[in] columnDelineator What character to print to delineate columns /// \param[in] columnDelineator What character to print to delineate columns
void PrintColumnHeaders(char *out, int outLength, char columnDelineator) const; void PrintColumnHeaders(char *out, int outLength, char columnDelineator) const;
/// \brief Writes a text representation of the row to \a out. /// \brief Writes a text representation of the row to \a out.
/// \param[out] out A pointer to an array of bytes which will hold the output. /// \param[out] out A pointer to an array of bytes which will hold the output.
/// \param[in] outLength The size of the \a out array /// \param[in] outLength The size of the \a out array
/// \param[in] columnDelineator What character to print to delineate columns /// \param[in] columnDelineator What character to print to delineate columns
/// \param[in] printDelineatorForBinary Binary output is not printed. True to still print the delineator. /// \param[in] printDelineatorForBinary Binary output is not printed. True to still print the delineator.
/// \param[in] inputRow The row to print /// \param[in] inputRow The row to print
void PrintRow(char *out, int outLength, char columnDelineator, bool printDelineatorForBinary, Table::Row* inputRow) const; void PrintRow(char *out, int outLength, char columnDelineator, bool printDelineatorForBinary, Table::Row* inputRow) const;
/// \brief Direct access to make things easier. /// \brief Direct access to make things easier.
const DataStructures::List<ColumnDescriptor>& GetColumns(void) const; const DataStructures::List<ColumnDescriptor>& GetColumns(void) const;
/// \brief Direct access to make things easier. /// \brief Direct access to make things easier.
const DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER>& GetRows(void) const; const DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER>& GetRows(void) const;
/// \brief Get the head of a linked list containing all the row data. /// \brief Get the head of a linked list containing all the row data.
DataStructures::Page<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER> * GetListHead(void); DataStructures::Page<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER> * GetListHead(void);
/// \brief Get the first free row id. /// \brief Get the first free row id.
/// This could be made more efficient. /// This could be made more efficient.
unsigned GetAvailableRowId(void) const; unsigned GetAvailableRowId(void) const;
Table& operator = ( const Table& input ); Table& operator = ( const Table& input );
protected: protected:
Table::Row* AddRowColumns(unsigned rowId, Row *row, DataStructures::List<unsigned> columnIndices); Table::Row* AddRowColumns(unsigned rowId, Row *row, DataStructures::List<unsigned> columnIndices);
void DeleteRow(Row *row); void DeleteRow(Row *row);
void QueryRow(DataStructures::List<unsigned> &inclusionFilterColumnIndices, DataStructures::List<unsigned> &columnIndicesToReturn, unsigned key, Table::Row* row, FilterQuery *inclusionFilters, Table *result); void QueryRow(DataStructures::List<unsigned> &inclusionFilterColumnIndices, DataStructures::List<unsigned> &columnIndicesToReturn, unsigned key, Table::Row* row, FilterQuery *inclusionFilters, Table *result);
// 16 is arbitrary and is the order of the BPlus tree. Higher orders are better for searching while lower orders are better for // 16 is arbitrary and is the order of the BPlus tree. Higher orders are better for searching while lower orders are better for
// Insertions and deletions. // Insertions and deletions.
DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER> rows; DataStructures::BPlusTree<unsigned, Row*, _TABLE_BPLUS_TREE_ORDER> rows;
// Columns in the table. // Columns in the table.
DataStructures::List<ColumnDescriptor> columns; DataStructures::List<ColumnDescriptor> columns;
}; };
} }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( pop ) #pragma warning( pop )
#endif #endif
#endif #endif

View File

@@ -1,143 +1,143 @@
/// \file DS_ThreadsafeAllocatingQueue.h /// \file DS_ThreadsafeAllocatingQueue.h
/// \internal /// \internal
/// A threadsafe queue, that also uses a memory pool for allocation /// A threadsafe queue, that also uses a memory pool for allocation
#ifndef __THREADSAFE_ALLOCATING_QUEUE #ifndef __THREADSAFE_ALLOCATING_QUEUE
#define __THREADSAFE_ALLOCATING_QUEUE #define __THREADSAFE_ALLOCATING_QUEUE
#include "DS_Queue.h" #include "DS_Queue.h"
#include "SimpleMutex.h" #include "SimpleMutex.h"
#include "DS_MemoryPool.h" #include "DS_MemoryPool.h"
// #if defined(new) // #if defined(new)
// #pragma push_macro("new") // #pragma push_macro("new")
// #undef new // #undef new
// #define RMO_NEW_UNDEF_ALLOCATING_QUEUE // #define RMO_NEW_UNDEF_ALLOCATING_QUEUE
// #endif // #endif
namespace DataStructures namespace DataStructures
{ {
template <class structureType> template <class structureType>
class RAK_DLL_EXPORT ThreadsafeAllocatingQueue class RAK_DLL_EXPORT ThreadsafeAllocatingQueue
{ {
public: public:
// Queue operations // Queue operations
void Push(structureType *s); void Push(structureType *s);
structureType *PopInaccurate(void); structureType *PopInaccurate(void);
structureType *Pop(void); structureType *Pop(void);
void SetPageSize(int size); void SetPageSize(int size);
bool IsEmpty(void); bool IsEmpty(void);
// Memory pool operations // Memory pool operations
structureType *Allocate(const char *file, unsigned int line); structureType *Allocate(const char *file, unsigned int line);
void Deallocate(structureType *s, const char *file, unsigned int line); void Deallocate(structureType *s, const char *file, unsigned int line);
void Clear(const char *file, unsigned int line); void Clear(const char *file, unsigned int line);
protected: protected:
MemoryPool<structureType> memoryPool; MemoryPool<structureType> memoryPool;
RakNet::SimpleMutex memoryPoolMutex; RakNet::SimpleMutex memoryPoolMutex;
Queue<structureType*> queue; Queue<structureType*> queue;
RakNet::SimpleMutex queueMutex; RakNet::SimpleMutex queueMutex;
}; };
template <class structureType> template <class structureType>
void ThreadsafeAllocatingQueue<structureType>::Push(structureType *s) void ThreadsafeAllocatingQueue<structureType>::Push(structureType *s)
{ {
queueMutex.Lock(); queueMutex.Lock();
queue.Push(s, _FILE_AND_LINE_ ); queue.Push(s, _FILE_AND_LINE_ );
queueMutex.Unlock(); queueMutex.Unlock();
} }
template <class structureType> template <class structureType>
structureType *ThreadsafeAllocatingQueue<structureType>::PopInaccurate(void) structureType *ThreadsafeAllocatingQueue<structureType>::PopInaccurate(void)
{ {
structureType *s; structureType *s;
if (queue.IsEmpty()) if (queue.IsEmpty())
return 0; return 0;
queueMutex.Lock(); queueMutex.Lock();
if (queue.IsEmpty()==false) if (queue.IsEmpty()==false)
s=queue.Pop(); s=queue.Pop();
else else
s=0; s=0;
queueMutex.Unlock(); queueMutex.Unlock();
return s; return s;
} }
template <class structureType> template <class structureType>
structureType *ThreadsafeAllocatingQueue<structureType>::Pop(void) structureType *ThreadsafeAllocatingQueue<structureType>::Pop(void)
{ {
structureType *s; structureType *s;
queueMutex.Lock(); queueMutex.Lock();
if (queue.IsEmpty()) if (queue.IsEmpty())
{ {
queueMutex.Unlock(); queueMutex.Unlock();
return 0; return 0;
} }
s=queue.Pop(); s=queue.Pop();
queueMutex.Unlock(); queueMutex.Unlock();
return s; return s;
} }
template <class structureType> template <class structureType>
structureType *ThreadsafeAllocatingQueue<structureType>::Allocate(const char *file, unsigned int line) structureType *ThreadsafeAllocatingQueue<structureType>::Allocate(const char *file, unsigned int line)
{ {
structureType *s; structureType *s;
memoryPoolMutex.Lock(); memoryPoolMutex.Lock();
s=memoryPool.Allocate(file, line); s=memoryPool.Allocate(file, line);
memoryPoolMutex.Unlock(); memoryPoolMutex.Unlock();
// Call new operator, memoryPool doesn't do this // Call new operator, memoryPool doesn't do this
s = new ((void*)s) structureType; s = new ((void*)s) structureType;
return s; return s;
} }
template <class structureType> template <class structureType>
void ThreadsafeAllocatingQueue<structureType>::Deallocate(structureType *s, const char *file, unsigned int line) void ThreadsafeAllocatingQueue<structureType>::Deallocate(structureType *s, const char *file, unsigned int line)
{ {
// Call delete operator, memory pool doesn't do this // Call delete operator, memory pool doesn't do this
s->~structureType(); s->~structureType();
memoryPoolMutex.Lock(); memoryPoolMutex.Lock();
memoryPool.Release(s, file, line); memoryPool.Release(s, file, line);
memoryPoolMutex.Unlock(); memoryPoolMutex.Unlock();
} }
template <class structureType> template <class structureType>
void ThreadsafeAllocatingQueue<structureType>::Clear(const char *file, unsigned int line) void ThreadsafeAllocatingQueue<structureType>::Clear(const char *file, unsigned int line)
{ {
memoryPoolMutex.Lock(); memoryPoolMutex.Lock();
for (unsigned int i=0; i < queue.Size(); i++) for (unsigned int i=0; i < queue.Size(); i++)
{ {
queue[i]->~structureType(); queue[i]->~structureType();
memoryPool.Release(queue[i], file, line); memoryPool.Release(queue[i], file, line);
} }
queue.Clear(file, line); queue.Clear(file, line);
memoryPoolMutex.Unlock(); memoryPoolMutex.Unlock();
memoryPoolMutex.Lock(); memoryPoolMutex.Lock();
memoryPool.Clear(file, line); memoryPool.Clear(file, line);
memoryPoolMutex.Unlock(); memoryPoolMutex.Unlock();
} }
template <class structureType> template <class structureType>
void ThreadsafeAllocatingQueue<structureType>::SetPageSize(int size) void ThreadsafeAllocatingQueue<structureType>::SetPageSize(int size)
{ {
memoryPool.SetPageSize(size); memoryPool.SetPageSize(size);
} }
template <class structureType> template <class structureType>
bool ThreadsafeAllocatingQueue<structureType>::IsEmpty(void) bool ThreadsafeAllocatingQueue<structureType>::IsEmpty(void)
{ {
bool isEmpty; bool isEmpty;
queueMutex.Lock(); queueMutex.Lock();
isEmpty=queue.IsEmpty(); isEmpty=queue.IsEmpty();
queueMutex.Unlock(); queueMutex.Unlock();
return isEmpty; return isEmpty;
} }
}; };
// #if defined(RMO_NEW_UNDEF_ALLOCATING_QUEUE) // #if defined(RMO_NEW_UNDEF_ALLOCATING_QUEUE)
// #pragma pop_macro("new") // #pragma pop_macro("new")
// #undef RMO_NEW_UNDEF_ALLOCATING_QUEUE // #undef RMO_NEW_UNDEF_ALLOCATING_QUEUE
// #endif // #endif
#endif #endif

View File

@@ -1,98 +1,98 @@
/// \file DS_Tree.h /// \file DS_Tree.h
/// \internal /// \internal
/// \brief Just a regular tree /// \brief Just a regular tree
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __DS_TREE_H #ifndef __DS_TREE_H
#define __DS_TREE_H #define __DS_TREE_H
#include "Export.h" #include "Export.h"
#include "DS_List.h" #include "DS_List.h"
#include "DS_Queue.h" #include "DS_Queue.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures /// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish. /// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures namespace DataStructures
{ {
template <class TreeType> template <class TreeType>
class RAK_DLL_EXPORT Tree class RAK_DLL_EXPORT Tree
{ {
public: public:
Tree(); Tree();
Tree(TreeType &inputData); Tree(TreeType &inputData);
~Tree(); ~Tree();
void LevelOrderTraversal(DataStructures::List<Tree*> &output); void LevelOrderTraversal(DataStructures::List<Tree*> &output);
void AddChild(TreeType &newData); void AddChild(TreeType &newData);
void DeleteDecendants(void); void DeleteDecendants(void);
TreeType data; TreeType data;
DataStructures::List<Tree *> children; DataStructures::List<Tree *> children;
}; };
template <class TreeType> template <class TreeType>
Tree<TreeType>::Tree() Tree<TreeType>::Tree()
{ {
} }
template <class TreeType> template <class TreeType>
Tree<TreeType>::Tree(TreeType &inputData) Tree<TreeType>::Tree(TreeType &inputData)
{ {
data=inputData; data=inputData;
} }
template <class TreeType> template <class TreeType>
Tree<TreeType>::~Tree() Tree<TreeType>::~Tree()
{ {
DeleteDecendants(); DeleteDecendants();
} }
template <class TreeType> template <class TreeType>
void Tree<TreeType>::LevelOrderTraversal(DataStructures::List<Tree*> &output) void Tree<TreeType>::LevelOrderTraversal(DataStructures::List<Tree*> &output)
{ {
unsigned i; unsigned i;
Tree<TreeType> *node; Tree<TreeType> *node;
DataStructures::Queue<Tree<TreeType>*> queue; DataStructures::Queue<Tree<TreeType>*> queue;
for (i=0; i < children.Size(); i++) for (i=0; i < children.Size(); i++)
queue.Push(children[i]); queue.Push(children[i]);
while (queue.Size()) while (queue.Size())
{ {
node=queue.Pop(); node=queue.Pop();
output.Insert(node, _FILE_AND_LINE_); output.Insert(node, _FILE_AND_LINE_);
for (i=0; i < node->children.Size(); i++) for (i=0; i < node->children.Size(); i++)
queue.Push(node->children[i]); queue.Push(node->children[i]);
} }
} }
template <class TreeType> template <class TreeType>
void Tree<TreeType>::AddChild(TreeType &newData) void Tree<TreeType>::AddChild(TreeType &newData)
{ {
children.Insert(RakNet::OP_NEW<Tree>(newData, _FILE_AND_LINE_)); children.Insert(RakNet::OP_NEW<Tree>(newData, _FILE_AND_LINE_));
} }
template <class TreeType> template <class TreeType>
void Tree<TreeType>::DeleteDecendants(void) void Tree<TreeType>::DeleteDecendants(void)
{ {
/* /*
DataStructures::List<Tree*> output; DataStructures::List<Tree*> output;
LevelOrderTraversal(output); LevelOrderTraversal(output);
unsigned i; unsigned i;
for (i=0; i < output.Size(); i++) for (i=0; i < output.Size(); i++)
RakNet::OP_DELETE(output[i], _FILE_AND_LINE_); RakNet::OP_DELETE(output[i], _FILE_AND_LINE_);
*/ */
// Already recursive to do this // Already recursive to do this
unsigned int i; unsigned int i;
for (i=0; i < children.Size(); i++) for (i=0; i < children.Size(); i++)
RakNet::OP_DELETE(children[i], _FILE_AND_LINE_); RakNet::OP_DELETE(children[i], _FILE_AND_LINE_);
} }
} }
#endif #endif

View File

@@ -1,63 +1,63 @@
#include "DataCompressor.h" #include "DataCompressor.h"
#include "DS_HuffmanEncodingTree.h" #include "DS_HuffmanEncodingTree.h"
#include "RakAssert.h" #include "RakAssert.h"
#include <string.h> // Use string.h rather than memory.h for a console #include <string.h> // Use string.h rather than memory.h for a console
using namespace RakNet; using namespace RakNet;
STATIC_FACTORY_DEFINITIONS(DataCompressor,DataCompressor) STATIC_FACTORY_DEFINITIONS(DataCompressor,DataCompressor)
void DataCompressor::Compress( unsigned char *userData, unsigned sizeInBytes, RakNet::BitStream * output ) void DataCompressor::Compress( unsigned char *userData, unsigned sizeInBytes, RakNet::BitStream * output )
{ {
// Don't use this for small files as you will just make them bigger! // Don't use this for small files as you will just make them bigger!
RakAssert(sizeInBytes > 2048); RakAssert(sizeInBytes > 2048);
unsigned int frequencyTable[ 256 ]; unsigned int frequencyTable[ 256 ];
unsigned int i; unsigned int i;
memset(frequencyTable,0,256*sizeof(unsigned int)); memset(frequencyTable,0,256*sizeof(unsigned int));
for (i=0; i < sizeInBytes; i++) for (i=0; i < sizeInBytes; i++)
++frequencyTable[userData[i]]; ++frequencyTable[userData[i]];
HuffmanEncodingTree tree; HuffmanEncodingTree tree;
BitSize_t writeOffset1, writeOffset2, bitsUsed1, bitsUsed2; BitSize_t writeOffset1, writeOffset2, bitsUsed1, bitsUsed2;
tree.GenerateFromFrequencyTable(frequencyTable); tree.GenerateFromFrequencyTable(frequencyTable);
output->WriteCompressed(sizeInBytes); output->WriteCompressed(sizeInBytes);
for (i=0; i < 256; i++) for (i=0; i < 256; i++)
output->WriteCompressed(frequencyTable[i]); output->WriteCompressed(frequencyTable[i]);
output->AlignWriteToByteBoundary(); output->AlignWriteToByteBoundary();
writeOffset1=output->GetWriteOffset(); writeOffset1=output->GetWriteOffset();
output->Write((unsigned int)0); // Dummy value output->Write((unsigned int)0); // Dummy value
bitsUsed1=output->GetNumberOfBitsUsed(); bitsUsed1=output->GetNumberOfBitsUsed();
tree.EncodeArray(userData, sizeInBytes, output); tree.EncodeArray(userData, sizeInBytes, output);
bitsUsed2=output->GetNumberOfBitsUsed(); bitsUsed2=output->GetNumberOfBitsUsed();
writeOffset2=output->GetWriteOffset(); writeOffset2=output->GetWriteOffset();
output->SetWriteOffset(writeOffset1); output->SetWriteOffset(writeOffset1);
output->Write(bitsUsed2-bitsUsed1); // Go back and write how many bits were used for the encoding output->Write(bitsUsed2-bitsUsed1); // Go back and write how many bits were used for the encoding
output->SetWriteOffset(writeOffset2); output->SetWriteOffset(writeOffset2);
} }
unsigned DataCompressor::DecompressAndAllocate( RakNet::BitStream * input, unsigned char **output ) unsigned DataCompressor::DecompressAndAllocate( RakNet::BitStream * input, unsigned char **output )
{ {
HuffmanEncodingTree tree; HuffmanEncodingTree tree;
unsigned int bitsUsed, destinationSizeInBytes; unsigned int bitsUsed, destinationSizeInBytes;
unsigned int decompressedBytes; unsigned int decompressedBytes;
unsigned int frequencyTable[ 256 ]; unsigned int frequencyTable[ 256 ];
unsigned i; unsigned i;
input->ReadCompressed(destinationSizeInBytes); input->ReadCompressed(destinationSizeInBytes);
for (i=0; i < 256; i++) for (i=0; i < 256; i++)
input->ReadCompressed(frequencyTable[i]); input->ReadCompressed(frequencyTable[i]);
input->AlignReadToByteBoundary(); input->AlignReadToByteBoundary();
if (input->Read(bitsUsed)==false) if (input->Read(bitsUsed)==false)
{ {
// Read error // Read error
#ifdef _DEBUG #ifdef _DEBUG
RakAssert(0); RakAssert(0);
#endif #endif
return 0; return 0;
} }
*output = (unsigned char*) rakMalloc_Ex(destinationSizeInBytes, _FILE_AND_LINE_); *output = (unsigned char*) rakMalloc_Ex(destinationSizeInBytes, _FILE_AND_LINE_);
tree.GenerateFromFrequencyTable(frequencyTable); tree.GenerateFromFrequencyTable(frequencyTable);
decompressedBytes=tree.DecodeArray(input, bitsUsed, destinationSizeInBytes, *output ); decompressedBytes=tree.DecodeArray(input, bitsUsed, destinationSizeInBytes, *output );
RakAssert(decompressedBytes==destinationSizeInBytes); RakAssert(decompressedBytes==destinationSizeInBytes);
return destinationSizeInBytes; return destinationSizeInBytes;
} }

View File

@@ -1,33 +1,33 @@
/// \file DataCompressor.h /// \file DataCompressor.h
/// \brief DataCompressor does compression on a block of data. /// \brief DataCompressor does compression on a block of data.
/// \details Not very good compression, but it's small and fast so is something you can use per-message at runtime. /// \details Not very good compression, but it's small and fast so is something you can use per-message at runtime.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#ifndef __DATA_COMPRESSOR_H #ifndef __DATA_COMPRESSOR_H
#define __DATA_COMPRESSOR_H #define __DATA_COMPRESSOR_H
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "DS_HuffmanEncodingTree.h" #include "DS_HuffmanEncodingTree.h"
#include "Export.h" #include "Export.h"
namespace RakNet namespace RakNet
{ {
/// \brief Does compression on a block of data. Not very good compression, but it's small and fast so is something you can compute at runtime. /// \brief Does compression on a block of data. Not very good compression, but it's small and fast so is something you can compute at runtime.
class RAK_DLL_EXPORT DataCompressor class RAK_DLL_EXPORT DataCompressor
{ {
public: public:
// GetInstance() and DestroyInstance(instance*) // GetInstance() and DestroyInstance(instance*)
STATIC_FACTORY_DECLARATIONS(DataCompressor) STATIC_FACTORY_DECLARATIONS(DataCompressor)
static void Compress( unsigned char *userData, unsigned sizeInBytes, RakNet::BitStream * output ); static void Compress( unsigned char *userData, unsigned sizeInBytes, RakNet::BitStream * output );
static unsigned DecompressAndAllocate( RakNet::BitStream * input, unsigned char **output ); static unsigned DecompressAndAllocate( RakNet::BitStream * input, unsigned char **output );
}; };
} // namespace RakNet } // namespace RakNet
#endif #endif

View File

@@ -1,242 +1,242 @@
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_DirectoryDeltaTransfer==1 && _RAKNET_SUPPORT_FileOperations==1 #if _RAKNET_SUPPORT_DirectoryDeltaTransfer==1 && _RAKNET_SUPPORT_FileOperations==1
#include "DirectoryDeltaTransfer.h" #include "DirectoryDeltaTransfer.h"
#include "FileList.h" #include "FileList.h"
#include "StringCompressor.h" #include "StringCompressor.h"
#include "RakPeerInterface.h" #include "RakPeerInterface.h"
#include "FileListTransfer.h" #include "FileListTransfer.h"
#include "FileListTransferCBInterface.h" #include "FileListTransferCBInterface.h"
#include "BitStream.h" #include "BitStream.h"
#include "MessageIdentifiers.h" #include "MessageIdentifiers.h"
#include "FileOperations.h" #include "FileOperations.h"
#include "IncrementalReadInterface.h" #include "IncrementalReadInterface.h"
using namespace RakNet; using namespace RakNet;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( push ) #pragma warning( push )
#endif #endif
class DDTCallback : public FileListTransferCBInterface class DDTCallback : public FileListTransferCBInterface
{ {
public: public:
unsigned subdirLen; unsigned subdirLen;
char outputSubdir[512]; char outputSubdir[512];
FileListTransferCBInterface *onFileCallback; FileListTransferCBInterface *onFileCallback;
DDTCallback() {} DDTCallback() {}
virtual ~DDTCallback() {} virtual ~DDTCallback() {}
virtual bool OnFile(OnFileStruct *onFileStruct) virtual bool OnFile(OnFileStruct *onFileStruct)
{ {
char fullPathToDir[1024]; char fullPathToDir[1024];
if (onFileStruct->fileName && onFileStruct->fileData && subdirLen < strlen(onFileStruct->fileName)) if (onFileStruct->fileName && onFileStruct->fileData && subdirLen < strlen(onFileStruct->fileName))
{ {
strcpy(fullPathToDir, outputSubdir); strcpy(fullPathToDir, outputSubdir);
strcat(fullPathToDir, onFileStruct->fileName+subdirLen); strcat(fullPathToDir, onFileStruct->fileName+subdirLen);
WriteFileWithDirectories(fullPathToDir, (char*)onFileStruct->fileData, (unsigned int ) onFileStruct->byteLengthOfThisFile); WriteFileWithDirectories(fullPathToDir, (char*)onFileStruct->fileData, (unsigned int ) onFileStruct->byteLengthOfThisFile);
} }
else else
fullPathToDir[0]=0; fullPathToDir[0]=0;
return onFileCallback->OnFile(onFileStruct); return onFileCallback->OnFile(onFileStruct);
} }
virtual void OnFileProgress(FileProgressStruct *fps) virtual void OnFileProgress(FileProgressStruct *fps)
{ {
char fullPathToDir[1024]; char fullPathToDir[1024];
if (fps->onFileStruct->fileName && subdirLen < strlen(fps->onFileStruct->fileName)) if (fps->onFileStruct->fileName && subdirLen < strlen(fps->onFileStruct->fileName))
{ {
strcpy(fullPathToDir, outputSubdir); strcpy(fullPathToDir, outputSubdir);
strcat(fullPathToDir, fps->onFileStruct->fileName+subdirLen); strcat(fullPathToDir, fps->onFileStruct->fileName+subdirLen);
} }
else else
fullPathToDir[0]=0; fullPathToDir[0]=0;
onFileCallback->OnFileProgress(fps); onFileCallback->OnFileProgress(fps);
} }
virtual bool OnDownloadComplete(DownloadCompleteStruct *dcs) virtual bool OnDownloadComplete(DownloadCompleteStruct *dcs)
{ {
return onFileCallback->OnDownloadComplete(dcs); return onFileCallback->OnDownloadComplete(dcs);
} }
}; };
STATIC_FACTORY_DEFINITIONS(DirectoryDeltaTransfer,DirectoryDeltaTransfer); STATIC_FACTORY_DEFINITIONS(DirectoryDeltaTransfer,DirectoryDeltaTransfer);
DirectoryDeltaTransfer::DirectoryDeltaTransfer() DirectoryDeltaTransfer::DirectoryDeltaTransfer()
{ {
applicationDirectory[0]=0; applicationDirectory[0]=0;
fileListTransfer=0; fileListTransfer=0;
availableUploads = RakNet::OP_NEW<FileList>( _FILE_AND_LINE_ ); availableUploads = RakNet::OP_NEW<FileList>( _FILE_AND_LINE_ );
priority=HIGH_PRIORITY; priority=HIGH_PRIORITY;
orderingChannel=0; orderingChannel=0;
incrementalReadInterface=0; incrementalReadInterface=0;
} }
DirectoryDeltaTransfer::~DirectoryDeltaTransfer() DirectoryDeltaTransfer::~DirectoryDeltaTransfer()
{ {
RakNet::OP_DELETE(availableUploads, _FILE_AND_LINE_); RakNet::OP_DELETE(availableUploads, _FILE_AND_LINE_);
} }
void DirectoryDeltaTransfer::SetFileListTransferPlugin(FileListTransfer *flt) void DirectoryDeltaTransfer::SetFileListTransferPlugin(FileListTransfer *flt)
{ {
if (fileListTransfer) if (fileListTransfer)
{ {
DataStructures::List<FileListProgress*> fileListProgressList; DataStructures::List<FileListProgress*> fileListProgressList;
fileListTransfer->GetCallbacks(fileListProgressList); fileListTransfer->GetCallbacks(fileListProgressList);
unsigned int i; unsigned int i;
for (i=0; i < fileListProgressList.Size(); i++) for (i=0; i < fileListProgressList.Size(); i++)
availableUploads->RemoveCallback(fileListProgressList[i]); availableUploads->RemoveCallback(fileListProgressList[i]);
} }
fileListTransfer=flt; fileListTransfer=flt;
if (flt) if (flt)
{ {
DataStructures::List<FileListProgress*> fileListProgressList; DataStructures::List<FileListProgress*> fileListProgressList;
flt->GetCallbacks(fileListProgressList); flt->GetCallbacks(fileListProgressList);
unsigned int i; unsigned int i;
for (i=0; i < fileListProgressList.Size(); i++) for (i=0; i < fileListProgressList.Size(); i++)
availableUploads->AddCallback(fileListProgressList[i]); availableUploads->AddCallback(fileListProgressList[i]);
} }
else else
{ {
availableUploads->ClearCallbacks(); availableUploads->ClearCallbacks();
} }
} }
void DirectoryDeltaTransfer::SetApplicationDirectory(const char *pathToApplication) void DirectoryDeltaTransfer::SetApplicationDirectory(const char *pathToApplication)
{ {
if (pathToApplication==0 || pathToApplication[0]==0) if (pathToApplication==0 || pathToApplication[0]==0)
applicationDirectory[0]=0; applicationDirectory[0]=0;
else else
{ {
strncpy(applicationDirectory, pathToApplication, 510); strncpy(applicationDirectory, pathToApplication, 510);
if (applicationDirectory[strlen(applicationDirectory)-1]!='/' && applicationDirectory[strlen(applicationDirectory)-1]!='\\') if (applicationDirectory[strlen(applicationDirectory)-1]!='/' && applicationDirectory[strlen(applicationDirectory)-1]!='\\')
strcat(applicationDirectory, "/"); strcat(applicationDirectory, "/");
applicationDirectory[511]=0; applicationDirectory[511]=0;
} }
} }
void DirectoryDeltaTransfer::SetUploadSendParameters(PacketPriority _priority, char _orderingChannel) void DirectoryDeltaTransfer::SetUploadSendParameters(PacketPriority _priority, char _orderingChannel)
{ {
priority=_priority; priority=_priority;
orderingChannel=_orderingChannel; orderingChannel=_orderingChannel;
} }
void DirectoryDeltaTransfer::AddUploadsFromSubdirectory(const char *subdir) void DirectoryDeltaTransfer::AddUploadsFromSubdirectory(const char *subdir)
{ {
availableUploads->AddFilesFromDirectory(applicationDirectory, subdir, true, false, true, FileListNodeContext(0,0)); availableUploads->AddFilesFromDirectory(applicationDirectory, subdir, true, false, true, FileListNodeContext(0,0));
} }
unsigned short DirectoryDeltaTransfer::DownloadFromSubdirectory(FileList &localFiles, const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb) unsigned short DirectoryDeltaTransfer::DownloadFromSubdirectory(FileList &localFiles, const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb)
{ {
RakAssert(host!=UNASSIGNED_SYSTEM_ADDRESS); RakAssert(host!=UNASSIGNED_SYSTEM_ADDRESS);
DDTCallback *transferCallback; DDTCallback *transferCallback;
localFiles.AddCallback(cb); localFiles.AddCallback(cb);
// Prepare the callback data // Prepare the callback data
transferCallback = RakNet::OP_NEW<DDTCallback>( _FILE_AND_LINE_ ); transferCallback = RakNet::OP_NEW<DDTCallback>( _FILE_AND_LINE_ );
if (subdir && subdir[0]) if (subdir && subdir[0])
{ {
transferCallback->subdirLen=(unsigned int)strlen(subdir); transferCallback->subdirLen=(unsigned int)strlen(subdir);
if (subdir[transferCallback->subdirLen-1]!='/' && subdir[transferCallback->subdirLen-1]!='\\') if (subdir[transferCallback->subdirLen-1]!='/' && subdir[transferCallback->subdirLen-1]!='\\')
transferCallback->subdirLen++; transferCallback->subdirLen++;
} }
else else
transferCallback->subdirLen=0; transferCallback->subdirLen=0;
if (prependAppDirToOutputSubdir) if (prependAppDirToOutputSubdir)
strcpy(transferCallback->outputSubdir, applicationDirectory); strcpy(transferCallback->outputSubdir, applicationDirectory);
else else
transferCallback->outputSubdir[0]=0; transferCallback->outputSubdir[0]=0;
if (outputSubdir) if (outputSubdir)
strcat(transferCallback->outputSubdir, outputSubdir); strcat(transferCallback->outputSubdir, outputSubdir);
if (transferCallback->outputSubdir[strlen(transferCallback->outputSubdir)-1]!='/' && transferCallback->outputSubdir[strlen(transferCallback->outputSubdir)-1]!='\\') if (transferCallback->outputSubdir[strlen(transferCallback->outputSubdir)-1]!='/' && transferCallback->outputSubdir[strlen(transferCallback->outputSubdir)-1]!='\\')
strcat(transferCallback->outputSubdir, "/"); strcat(transferCallback->outputSubdir, "/");
transferCallback->onFileCallback=onFileCallback; transferCallback->onFileCallback=onFileCallback;
// Setup the transfer plugin to get the response to this download request // Setup the transfer plugin to get the response to this download request
unsigned short setId = fileListTransfer->SetupReceive(transferCallback, true, host); unsigned short setId = fileListTransfer->SetupReceive(transferCallback, true, host);
// Send to the host, telling it to process this request // Send to the host, telling it to process this request
RakNet::BitStream outBitstream; RakNet::BitStream outBitstream;
outBitstream.Write((MessageID)ID_DDT_DOWNLOAD_REQUEST); outBitstream.Write((MessageID)ID_DDT_DOWNLOAD_REQUEST);
outBitstream.Write(setId); outBitstream.Write(setId);
StringCompressor::Instance()->EncodeString(subdir, 256, &outBitstream); StringCompressor::Instance()->EncodeString(subdir, 256, &outBitstream);
StringCompressor::Instance()->EncodeString(outputSubdir, 256, &outBitstream); StringCompressor::Instance()->EncodeString(outputSubdir, 256, &outBitstream);
localFiles.Serialize(&outBitstream); localFiles.Serialize(&outBitstream);
SendUnified(&outBitstream, _priority, RELIABLE_ORDERED, _orderingChannel, host, false); SendUnified(&outBitstream, _priority, RELIABLE_ORDERED, _orderingChannel, host, false);
return setId; return setId;
} }
unsigned short DirectoryDeltaTransfer::DownloadFromSubdirectory(const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb) unsigned short DirectoryDeltaTransfer::DownloadFromSubdirectory(const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb)
{ {
FileList localFiles; FileList localFiles;
// Get a hash of all the files that we already have (if any) // Get a hash of all the files that we already have (if any)
localFiles.AddFilesFromDirectory(prependAppDirToOutputSubdir ? applicationDirectory : 0, outputSubdir, true, false, true, FileListNodeContext(0,0)); localFiles.AddFilesFromDirectory(prependAppDirToOutputSubdir ? applicationDirectory : 0, outputSubdir, true, false, true, FileListNodeContext(0,0));
return DownloadFromSubdirectory(localFiles, subdir, outputSubdir, prependAppDirToOutputSubdir, host, onFileCallback, _priority, _orderingChannel, cb); return DownloadFromSubdirectory(localFiles, subdir, outputSubdir, prependAppDirToOutputSubdir, host, onFileCallback, _priority, _orderingChannel, cb);
} }
void DirectoryDeltaTransfer::GenerateHashes(FileList &localFiles, const char *outputSubdir, bool prependAppDirToOutputSubdir) void DirectoryDeltaTransfer::GenerateHashes(FileList &localFiles, const char *outputSubdir, bool prependAppDirToOutputSubdir)
{ {
localFiles.AddFilesFromDirectory(prependAppDirToOutputSubdir ? applicationDirectory : 0, outputSubdir, true, false, true, FileListNodeContext(0,0)); localFiles.AddFilesFromDirectory(prependAppDirToOutputSubdir ? applicationDirectory : 0, outputSubdir, true, false, true, FileListNodeContext(0,0));
} }
void DirectoryDeltaTransfer::ClearUploads(void) void DirectoryDeltaTransfer::ClearUploads(void)
{ {
availableUploads->Clear(); availableUploads->Clear();
} }
void DirectoryDeltaTransfer::OnDownloadRequest(Packet *packet) void DirectoryDeltaTransfer::OnDownloadRequest(Packet *packet)
{ {
char subdir[256]; char subdir[256];
char remoteSubdir[256]; char remoteSubdir[256];
RakNet::BitStream inBitstream(packet->data, packet->length, false); RakNet::BitStream inBitstream(packet->data, packet->length, false);
FileList remoteFileHash; FileList remoteFileHash;
FileList delta; FileList delta;
unsigned short setId; unsigned short setId;
inBitstream.IgnoreBits(8); inBitstream.IgnoreBits(8);
inBitstream.Read(setId); inBitstream.Read(setId);
StringCompressor::Instance()->DecodeString(subdir, 256, &inBitstream); StringCompressor::Instance()->DecodeString(subdir, 256, &inBitstream);
StringCompressor::Instance()->DecodeString(remoteSubdir, 256, &inBitstream); StringCompressor::Instance()->DecodeString(remoteSubdir, 256, &inBitstream);
if (remoteFileHash.Deserialize(&inBitstream)==false) if (remoteFileHash.Deserialize(&inBitstream)==false)
{ {
#ifdef _DEBUG #ifdef _DEBUG
RakAssert(0); RakAssert(0);
#endif #endif
return; return;
} }
availableUploads->GetDeltaToCurrent(&remoteFileHash, &delta, subdir, remoteSubdir); availableUploads->GetDeltaToCurrent(&remoteFileHash, &delta, subdir, remoteSubdir);
if (incrementalReadInterface==0) if (incrementalReadInterface==0)
delta.PopulateDataFromDisk(applicationDirectory, true, false, true); delta.PopulateDataFromDisk(applicationDirectory, true, false, true);
else else
delta.FlagFilesAsReferences(); delta.FlagFilesAsReferences();
// This will call the ddtCallback interface that was passed to FileListTransfer::SetupReceive on the remote system // This will call the ddtCallback interface that was passed to FileListTransfer::SetupReceive on the remote system
fileListTransfer->Send(&delta, rakPeerInterface, packet->systemAddress, setId, priority, orderingChannel, incrementalReadInterface, chunkSize); fileListTransfer->Send(&delta, rakPeerInterface, packet->systemAddress, setId, priority, orderingChannel, incrementalReadInterface, chunkSize);
} }
PluginReceiveResult DirectoryDeltaTransfer::OnReceive(Packet *packet) PluginReceiveResult DirectoryDeltaTransfer::OnReceive(Packet *packet)
{ {
switch (packet->data[0]) switch (packet->data[0])
{ {
case ID_DDT_DOWNLOAD_REQUEST: case ID_DDT_DOWNLOAD_REQUEST:
OnDownloadRequest(packet); OnDownloadRequest(packet);
return RR_STOP_PROCESSING_AND_DEALLOCATE; return RR_STOP_PROCESSING_AND_DEALLOCATE;
} }
return RR_CONTINUE_PROCESSING; return RR_CONTINUE_PROCESSING;
} }
unsigned DirectoryDeltaTransfer::GetNumberOfFilesForUpload(void) const unsigned DirectoryDeltaTransfer::GetNumberOfFilesForUpload(void) const
{ {
return availableUploads->fileList.Size(); return availableUploads->fileList.Size();
} }
void DirectoryDeltaTransfer::SetDownloadRequestIncrementalReadInterface(IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize) void DirectoryDeltaTransfer::SetDownloadRequestIncrementalReadInterface(IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize)
{ {
incrementalReadInterface=_incrementalReadInterface; incrementalReadInterface=_incrementalReadInterface;
chunkSize=_chunkSize; chunkSize=_chunkSize;
} }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( pop ) #pragma warning( pop )
#endif #endif
#endif // _RAKNET_SUPPORT_* #endif // _RAKNET_SUPPORT_*

View File

@@ -1,164 +1,164 @@
/// \file DirectoryDeltaTransfer.h /// \file DirectoryDeltaTransfer.h
/// \brief Simple class to send changes between directories. /// \brief Simple class to send changes between directories.
/// \details In essence, a simple autopatcher that can be used for transmitting levels, skins, etc. /// \details In essence, a simple autopatcher that can be used for transmitting levels, skins, etc.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_DirectoryDeltaTransfer==1 && _RAKNET_SUPPORT_FileOperations==1 #if _RAKNET_SUPPORT_DirectoryDeltaTransfer==1 && _RAKNET_SUPPORT_FileOperations==1
#ifndef __DIRECTORY_DELTA_TRANSFER_H #ifndef __DIRECTORY_DELTA_TRANSFER_H
#define __DIRECTORY_DELTA_TRANSFER_H #define __DIRECTORY_DELTA_TRANSFER_H
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "RakNetTypes.h" #include "RakNetTypes.h"
#include "Export.h" #include "Export.h"
#include "PluginInterface2.h" #include "PluginInterface2.h"
#include "DS_Map.h" #include "DS_Map.h"
#include "PacketPriority.h" #include "PacketPriority.h"
/// \defgroup DIRECTORY_DELTA_TRANSFER_GROUP DirectoryDeltaTransfer /// \defgroup DIRECTORY_DELTA_TRANSFER_GROUP DirectoryDeltaTransfer
/// \brief Simple class to send changes between directories /// \brief Simple class to send changes between directories
/// \details /// \details
/// \ingroup PLUGINS_GROUP /// \ingroup PLUGINS_GROUP
/// \brief Simple class to send changes between directories. In essence, a simple autopatcher that can be used for transmitting levels, skins, etc. /// \brief Simple class to send changes between directories. In essence, a simple autopatcher that can be used for transmitting levels, skins, etc.
/// \details /// \details
/// \sa AutopatcherClient class for database driven patching, including binary deltas and search by date. /// \sa AutopatcherClient class for database driven patching, including binary deltas and search by date.
/// ///
/// To use, first set the path to your application. For example "C:/Games/MyRPG/"<BR> /// To use, first set the path to your application. For example "C:/Games/MyRPG/"<BR>
/// To allow other systems to download files, call AddUploadsFromSubdirectory, where the parameter is a path relative<BR> /// To allow other systems to download files, call AddUploadsFromSubdirectory, where the parameter is a path relative<BR>
/// to the path to your application. This includes subdirectories.<BR> /// to the path to your application. This includes subdirectories.<BR>
/// For example:<BR> /// For example:<BR>
/// SetApplicationDirectory("C:/Games/MyRPG/");<BR> /// SetApplicationDirectory("C:/Games/MyRPG/");<BR>
/// AddUploadsFromSubdirectory("Mods/Skins/");<BR> /// AddUploadsFromSubdirectory("Mods/Skins/");<BR>
/// would allow downloads from<BR> /// would allow downloads from<BR>
/// "C:/Games/MyRPG/Mods/Skins/*.*" as well as "C:/Games/MyRPG/Mods/Skins/Level1/*.*"<BR> /// "C:/Games/MyRPG/Mods/Skins/*.*" as well as "C:/Games/MyRPG/Mods/Skins/Level1/*.*"<BR>
/// It would NOT allow downloads from C:/Games/MyRPG/Levels, nor would it allow downloads from C:/Windows<BR> /// It would NOT allow downloads from C:/Games/MyRPG/Levels, nor would it allow downloads from C:/Windows<BR>
/// While pathToApplication can be anything you want, applicationSubdirectory must match either partially or fully between systems. /// While pathToApplication can be anything you want, applicationSubdirectory must match either partially or fully between systems.
/// \ingroup DIRECTORY_DELTA_TRANSFER_GROUP /// \ingroup DIRECTORY_DELTA_TRANSFER_GROUP
namespace RakNet namespace RakNet
{ {
/// Forward declarations /// Forward declarations
class RakPeerInterface; class RakPeerInterface;
class FileList; class FileList;
struct Packet; struct Packet;
struct InternalPacket; struct InternalPacket;
struct DownloadRequest; struct DownloadRequest;
class FileListTransfer; class FileListTransfer;
class FileListTransferCBInterface; class FileListTransferCBInterface;
class FileListProgress; class FileListProgress;
class IncrementalReadInterface; class IncrementalReadInterface;
class RAK_DLL_EXPORT DirectoryDeltaTransfer : public PluginInterface2 class RAK_DLL_EXPORT DirectoryDeltaTransfer : public PluginInterface2
{ {
public: public:
// GetInstance() and DestroyInstance(instance*) // GetInstance() and DestroyInstance(instance*)
STATIC_FACTORY_DECLARATIONS(DirectoryDeltaTransfer) STATIC_FACTORY_DECLARATIONS(DirectoryDeltaTransfer)
// Constructor // Constructor
DirectoryDeltaTransfer(); DirectoryDeltaTransfer();
// Destructor // Destructor
virtual ~DirectoryDeltaTransfer(); virtual ~DirectoryDeltaTransfer();
/// \brief This plugin has a dependency on the FileListTransfer plugin, which it uses to actually send the files. /// \brief This plugin has a dependency on the FileListTransfer plugin, which it uses to actually send the files.
/// \details So you need an instance of that plugin registered with RakPeerInterface, and a pointer to that interface should be passed here. /// \details So you need an instance of that plugin registered with RakPeerInterface, and a pointer to that interface should be passed here.
/// \param[in] flt A pointer to a registered instance of FileListTransfer /// \param[in] flt A pointer to a registered instance of FileListTransfer
void SetFileListTransferPlugin(FileListTransfer *flt); void SetFileListTransferPlugin(FileListTransfer *flt);
/// \brief Set the local root directory to base all file uploads and downloads off of. /// \brief Set the local root directory to base all file uploads and downloads off of.
/// \param[in] pathToApplication This path will be prepended to \a applicationSubdirectory in AddUploadsFromSubdirectory to find the actual path on disk. /// \param[in] pathToApplication This path will be prepended to \a applicationSubdirectory in AddUploadsFromSubdirectory to find the actual path on disk.
void SetApplicationDirectory(const char *pathToApplication); void SetApplicationDirectory(const char *pathToApplication);
/// \brief What parameters to use for the RakPeerInterface::Send() call when uploading files. /// \brief What parameters to use for the RakPeerInterface::Send() call when uploading files.
/// \param[in] _priority See RakPeerInterface::Send() /// \param[in] _priority See RakPeerInterface::Send()
/// \param[in] _orderingChannel See RakPeerInterface::Send() /// \param[in] _orderingChannel See RakPeerInterface::Send()
void SetUploadSendParameters(PacketPriority _priority, char _orderingChannel); void SetUploadSendParameters(PacketPriority _priority, char _orderingChannel);
/// \brief Add all files in the specified subdirectory recursively. /// \brief Add all files in the specified subdirectory recursively.
/// \details \a subdir is appended to \a pathToApplication in SetApplicationDirectory(). /// \details \a subdir is appended to \a pathToApplication in SetApplicationDirectory().
/// All files in the resultant directory and subdirectories are then hashed so that users can download them. /// All files in the resultant directory and subdirectories are then hashed so that users can download them.
/// \pre You must call SetFileListTransferPlugin with a valid FileListTransfer plugin /// \pre You must call SetFileListTransferPlugin with a valid FileListTransfer plugin
/// \param[in] subdir Concatenated with pathToApplication to form the final path from which to allow uploads. /// \param[in] subdir Concatenated with pathToApplication to form the final path from which to allow uploads.
void AddUploadsFromSubdirectory(const char *subdir); void AddUploadsFromSubdirectory(const char *subdir);
/// \brief Downloads files from the matching parameter \a subdir in AddUploadsFromSubdirectory. /// \brief Downloads files from the matching parameter \a subdir in AddUploadsFromSubdirectory.
/// \details \a subdir must contain all starting characters in \a subdir in AddUploadsFromSubdirectory /// \details \a subdir must contain all starting characters in \a subdir in AddUploadsFromSubdirectory
/// Therefore, /// Therefore,
/// AddUploadsFromSubdirectory("Levels/Level1/"); would allow you to download using DownloadFromSubdirectory("Levels/Level1/Textures/"... /// AddUploadsFromSubdirectory("Levels/Level1/"); would allow you to download using DownloadFromSubdirectory("Levels/Level1/Textures/"...
/// but it would NOT allow you to download from DownloadFromSubdirectory("Levels/"... or DownloadFromSubdirectory("Levels/Level2/"... /// but it would NOT allow you to download from DownloadFromSubdirectory("Levels/"... or DownloadFromSubdirectory("Levels/Level2/"...
/// \pre You must call SetFileListTransferPlugin with a valid FileListTransfer plugin /// \pre You must call SetFileListTransferPlugin with a valid FileListTransfer plugin
/// \note Blocking. Will block while hashes of the local files are generated /// \note Blocking. Will block while hashes of the local files are generated
/// \param[in] subdir A directory passed to AddUploadsFromSubdirectory on the remote system. The passed dir can be more specific than the remote dir. /// \param[in] subdir A directory passed to AddUploadsFromSubdirectory on the remote system. The passed dir can be more specific than the remote dir.
/// \param[in] outputSubdir The directory to write the output to. Usually this will match \a subdir but it can be different if you want. /// \param[in] outputSubdir The directory to write the output to. Usually this will match \a subdir but it can be different if you want.
/// \param[in] prependAppDirToOutputSubdir True to prepend outputSubdir with pathToApplication when determining the final output path. Usually you want this to be true. /// \param[in] prependAppDirToOutputSubdir True to prepend outputSubdir with pathToApplication when determining the final output path. Usually you want this to be true.
/// \param[in] host The address of the remote system to send the message to. /// \param[in] host The address of the remote system to send the message to.
/// \param[in] onFileCallback Callback to call per-file (optional). When fileIndex+1==setCount in the callback then the download is done /// \param[in] onFileCallback Callback to call per-file (optional). When fileIndex+1==setCount in the callback then the download is done
/// \param[in] _priority See RakPeerInterface::Send() /// \param[in] _priority See RakPeerInterface::Send()
/// \param[in] _orderingChannel See RakPeerInterface::Send() /// \param[in] _orderingChannel See RakPeerInterface::Send()
/// \param[in] cb Callback to get progress updates. Pass 0 to not use. /// \param[in] cb Callback to get progress updates. Pass 0 to not use.
/// \return A set ID, identifying this download set. Returns 65535 on host unreachable. /// \return A set ID, identifying this download set. Returns 65535 on host unreachable.
unsigned short DownloadFromSubdirectory(const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb); unsigned short DownloadFromSubdirectory(const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb);
/// \brief Downloads files from the matching parameter \a subdir in AddUploadsFromSubdirectory. /// \brief Downloads files from the matching parameter \a subdir in AddUploadsFromSubdirectory.
/// \details \a subdir must contain all starting characters in \a subdir in AddUploadsFromSubdirectory /// \details \a subdir must contain all starting characters in \a subdir in AddUploadsFromSubdirectory
/// Therefore, /// Therefore,
/// AddUploadsFromSubdirectory("Levels/Level1/"); would allow you to download using DownloadFromSubdirectory("Levels/Level1/Textures/"... /// AddUploadsFromSubdirectory("Levels/Level1/"); would allow you to download using DownloadFromSubdirectory("Levels/Level1/Textures/"...
/// but it would NOT allow you to download from DownloadFromSubdirectory("Levels/"... or DownloadFromSubdirectory("Levels/Level2/"... /// but it would NOT allow you to download from DownloadFromSubdirectory("Levels/"... or DownloadFromSubdirectory("Levels/Level2/"...
/// \pre You must call SetFileListTransferPlugin with a valid FileListTransfer plugin /// \pre You must call SetFileListTransferPlugin with a valid FileListTransfer plugin
/// \note Nonblocking, but requires call to GenerateHashes() /// \note Nonblocking, but requires call to GenerateHashes()
/// \param[in] localFiles Hashes of local files already on the harddrive. Populate with GenerateHashes(), which you may wish to call from a thread /// \param[in] localFiles Hashes of local files already on the harddrive. Populate with GenerateHashes(), which you may wish to call from a thread
/// \param[in] subdir A directory passed to AddUploadsFromSubdirectory on the remote system. The passed dir can be more specific than the remote dir. /// \param[in] subdir A directory passed to AddUploadsFromSubdirectory on the remote system. The passed dir can be more specific than the remote dir.
/// \param[in] outputSubdir The directory to write the output to. Usually this will match \a subdir but it can be different if you want. /// \param[in] outputSubdir The directory to write the output to. Usually this will match \a subdir but it can be different if you want.
/// \param[in] prependAppDirToOutputSubdir True to prepend outputSubdir with pathToApplication when determining the final output path. Usually you want this to be true. /// \param[in] prependAppDirToOutputSubdir True to prepend outputSubdir with pathToApplication when determining the final output path. Usually you want this to be true.
/// \param[in] host The address of the remote system to send the message to. /// \param[in] host The address of the remote system to send the message to.
/// \param[in] onFileCallback Callback to call per-file (optional). When fileIndex+1==setCount in the callback then the download is done /// \param[in] onFileCallback Callback to call per-file (optional). When fileIndex+1==setCount in the callback then the download is done
/// \param[in] _priority See RakPeerInterface::Send() /// \param[in] _priority See RakPeerInterface::Send()
/// \param[in] _orderingChannel See RakPeerInterface::Send() /// \param[in] _orderingChannel See RakPeerInterface::Send()
/// \param[in] cb Callback to get progress updates. Pass 0 to not use. /// \param[in] cb Callback to get progress updates. Pass 0 to not use.
/// \return A set ID, identifying this download set. Returns 65535 on host unreachable. /// \return A set ID, identifying this download set. Returns 65535 on host unreachable.
unsigned short DownloadFromSubdirectory(FileList &localFiles, const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb); unsigned short DownloadFromSubdirectory(FileList &localFiles, const char *subdir, const char *outputSubdir, bool prependAppDirToOutputSubdir, SystemAddress host, FileListTransferCBInterface *onFileCallback, PacketPriority _priority, char _orderingChannel, FileListProgress *cb);
/// Hash files already on the harddrive, in preparation for a call to DownloadFromSubdirectory(). Passed to second version of DownloadFromSubdirectory() /// Hash files already on the harddrive, in preparation for a call to DownloadFromSubdirectory(). Passed to second version of DownloadFromSubdirectory()
/// This is slow, and it is exposed so you can call it from a thread before calling DownloadFromSubdirectory() /// This is slow, and it is exposed so you can call it from a thread before calling DownloadFromSubdirectory()
/// \param[out] localFiles List of hashed files populated from \a outputSubdir and \a prependAppDirToOutputSubdir /// \param[out] localFiles List of hashed files populated from \a outputSubdir and \a prependAppDirToOutputSubdir
/// \param[in] outputSubdir The directory to write the output to. Usually this will match \a subdir but it can be different if you want. /// \param[in] outputSubdir The directory to write the output to. Usually this will match \a subdir but it can be different if you want.
/// \param[in] prependAppDirToOutputSubdir True to prepend outputSubdir with pathToApplication when determining the final output path. Usually you want this to be true. /// \param[in] prependAppDirToOutputSubdir True to prepend outputSubdir with pathToApplication when determining the final output path. Usually you want this to be true.
void GenerateHashes(FileList &localFiles, const char *outputSubdir, bool prependAppDirToOutputSubdir); void GenerateHashes(FileList &localFiles, const char *outputSubdir, bool prependAppDirToOutputSubdir);
/// \brief Clear all allowed uploads previously set with AddUploadsFromSubdirectory /// \brief Clear all allowed uploads previously set with AddUploadsFromSubdirectory
void ClearUploads(void); void ClearUploads(void);
/// \brief Returns how many files are available for upload /// \brief Returns how many files are available for upload
/// \return How many files are available for upload /// \return How many files are available for upload
unsigned GetNumberOfFilesForUpload(void) const; unsigned GetNumberOfFilesForUpload(void) const;
/// \brief Normally, if a remote system requests files, those files are all loaded into memory and sent immediately. /// \brief Normally, if a remote system requests files, those files are all loaded into memory and sent immediately.
/// \details This function allows the files to be read in incremental chunks, saving memory /// \details This function allows the files to be read in incremental chunks, saving memory
/// \param[in] _incrementalReadInterface If a file in \a fileList has no data, filePullInterface will be used to read the file in chunks of size \a chunkSize /// \param[in] _incrementalReadInterface If a file in \a fileList has no data, filePullInterface will be used to read the file in chunks of size \a chunkSize
/// \param[in] _chunkSize How large of a block of a file to send at once /// \param[in] _chunkSize How large of a block of a file to send at once
void SetDownloadRequestIncrementalReadInterface(IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize); void SetDownloadRequestIncrementalReadInterface(IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize);
/// \internal For plugin handling /// \internal For plugin handling
virtual PluginReceiveResult OnReceive(Packet *packet); virtual PluginReceiveResult OnReceive(Packet *packet);
protected: protected:
void OnDownloadRequest(Packet *packet); void OnDownloadRequest(Packet *packet);
char applicationDirectory[512]; char applicationDirectory[512];
FileListTransfer *fileListTransfer; FileListTransfer *fileListTransfer;
FileList *availableUploads; FileList *availableUploads;
PacketPriority priority; PacketPriority priority;
char orderingChannel; char orderingChannel;
IncrementalReadInterface *incrementalReadInterface; IncrementalReadInterface *incrementalReadInterface;
unsigned int chunkSize; unsigned int chunkSize;
}; };
} // namespace RakNet } // namespace RakNet
#endif #endif
#endif // _RAKNET_SUPPORT_* #endif // _RAKNET_SUPPORT_*

View File

@@ -1,236 +1,236 @@
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_DynDNS==1 && _RAKNET_SUPPORT_TCPInterface==1 #if _RAKNET_SUPPORT_DynDNS==1 && _RAKNET_SUPPORT_TCPInterface==1
#include "TCPInterface.h" #include "TCPInterface.h"
#include "SocketLayer.h" #include "SocketLayer.h"
#include "DynDNS.h" #include "DynDNS.h"
#include "GetTime.h" #include "GetTime.h"
using namespace RakNet; using namespace RakNet;
struct DynDnsResult struct DynDnsResult
{ {
const char *description; const char *description;
const char *code; const char *code;
DynDnsResultCode resultCode; DynDnsResultCode resultCode;
}; };
DynDnsResult resultTable[13] = DynDnsResult resultTable[13] =
{ {
// See http://www.dyndns.com/developers/specs/flow.pdf // See http://www.dyndns.com/developers/specs/flow.pdf
{"DNS update success.\nPlease wait up to 60 seconds for the change to take effect.\n", "good", RC_SUCCESS}, // Even with success, it takes time for the cache to update! {"DNS update success.\nPlease wait up to 60 seconds for the change to take effect.\n", "good", RC_SUCCESS}, // Even with success, it takes time for the cache to update!
{"No change", "nochg", RC_NO_CHANGE}, {"No change", "nochg", RC_NO_CHANGE},
{"Host has been blocked. You will need to contact DynDNS to reenable.", "abuse", RC_ABUSE}, {"Host has been blocked. You will need to contact DynDNS to reenable.", "abuse", RC_ABUSE},
{"Useragent is blocked", "badagent", RC_BAD_AGENT}, {"Useragent is blocked", "badagent", RC_BAD_AGENT},
{"Username/password pair bad", "badauth", RC_BAD_AUTH}, {"Username/password pair bad", "badauth", RC_BAD_AUTH},
{"Bad system parameter", "badsys", RC_BAD_SYS}, {"Bad system parameter", "badsys", RC_BAD_SYS},
{"DNS inconsistency", "dnserr", RC_DNS_ERROR}, {"DNS inconsistency", "dnserr", RC_DNS_ERROR},
{"Paid account feature", "!donator", RC_NOT_DONATOR}, {"Paid account feature", "!donator", RC_NOT_DONATOR},
{"No such host in system", "nohost", RC_NO_HOST}, {"No such host in system", "nohost", RC_NO_HOST},
{"Invalid hostname format", "notfqdn", RC_NOT_FQDN}, {"Invalid hostname format", "notfqdn", RC_NOT_FQDN},
{"Serious error", "numhost", RC_NUM_HOST}, {"Serious error", "numhost", RC_NUM_HOST},
{"This host exists, but does not belong to you", "!yours", RC_NOT_YOURS}, {"This host exists, but does not belong to you", "!yours", RC_NOT_YOURS},
{"911", "911", RC_911}, {"911", "911", RC_911},
}; };
DynDNS::DynDNS() DynDNS::DynDNS()
{ {
connectPhase=CP_IDLE; connectPhase=CP_IDLE;
tcp=0; tcp=0;
} }
DynDNS::~DynDNS() DynDNS::~DynDNS()
{ {
if (tcp) if (tcp)
RakNet::OP_DELETE(tcp, _FILE_AND_LINE_); RakNet::OP_DELETE(tcp, _FILE_AND_LINE_);
} }
void DynDNS::Stop(void) void DynDNS::Stop(void)
{ {
tcp->Stop(); tcp->Stop();
connectPhase = CP_IDLE; connectPhase = CP_IDLE;
RakNet::OP_DELETE(tcp, _FILE_AND_LINE_); RakNet::OP_DELETE(tcp, _FILE_AND_LINE_);
tcp=0; tcp=0;
} }
// newIPAddress is optional - if left out, DynDNS will use whatever it receives // newIPAddress is optional - if left out, DynDNS will use whatever it receives
void DynDNS::UpdateHostIP(const char *dnsHost, const char *newIPAddress, const char *usernameAndPassword ) void DynDNS::UpdateHostIP(const char *dnsHost, const char *newIPAddress, const char *usernameAndPassword )
{ {
myIPStr[0]=0; myIPStr[0]=0;
if (tcp==0) if (tcp==0)
tcp = RakNet::OP_NEW<TCPInterface>(_FILE_AND_LINE_); tcp = RakNet::OP_NEW<TCPInterface>(_FILE_AND_LINE_);
connectPhase = CP_IDLE; connectPhase = CP_IDLE;
host = dnsHost; host = dnsHost;
if (tcp->Start(0, 1)==false) if (tcp->Start(0, 1)==false)
{ {
SetCompleted(RC_TCP_FAILED_TO_START, "TCP failed to start"); SetCompleted(RC_TCP_FAILED_TO_START, "TCP failed to start");
return; return;
} }
connectPhase = CP_CONNECTING_TO_CHECKIP; connectPhase = CP_CONNECTING_TO_CHECKIP;
tcp->Connect("checkip.dyndns.org", 80, false); tcp->Connect("checkip.dyndns.org", 80, false);
// See https://www.dyndns.com/developers/specs/syntax.html // See https://www.dyndns.com/developers/specs/syntax.html
getString="GET /nic/update?hostname="; getString="GET /nic/update?hostname=";
getString+=dnsHost; getString+=dnsHost;
if (newIPAddress) if (newIPAddress)
{ {
getString+="&myip="; getString+="&myip=";
getString+=newIPAddress; getString+=newIPAddress;
} }
getString+="&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG HTTP/1.0\n"; getString+="&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG HTTP/1.0\n";
getString+="Host: members.dyndns.org\n"; getString+="Host: members.dyndns.org\n";
getString+="Authorization: Basic "; getString+="Authorization: Basic ";
char outputData[512]; char outputData[512];
TCPInterface::Base64Encoding(usernameAndPassword, (int) strlen(usernameAndPassword), outputData); TCPInterface::Base64Encoding(usernameAndPassword, (int) strlen(usernameAndPassword), outputData);
getString+=outputData; getString+=outputData;
getString+="User-Agent: Jenkins Software LLC - PC - 1.0\n\n"; getString+="User-Agent: Jenkins Software LLC - PC - 1.0\n\n";
} }
void DynDNS::Update(void) void DynDNS::Update(void)
{ {
if (connectPhase==CP_IDLE) if (connectPhase==CP_IDLE)
return; return;
serverAddress=tcp->HasFailedConnectionAttempt(); serverAddress=tcp->HasFailedConnectionAttempt();
if (serverAddress!=UNASSIGNED_SYSTEM_ADDRESS) if (serverAddress!=UNASSIGNED_SYSTEM_ADDRESS)
{ {
SetCompleted(RC_TCP_DID_NOT_CONNECT, "Could not connect to DynDNS"); SetCompleted(RC_TCP_DID_NOT_CONNECT, "Could not connect to DynDNS");
return; return;
} }
serverAddress=tcp->HasCompletedConnectionAttempt(); serverAddress=tcp->HasCompletedConnectionAttempt();
if (serverAddress!=UNASSIGNED_SYSTEM_ADDRESS) if (serverAddress!=UNASSIGNED_SYSTEM_ADDRESS)
{ {
if (connectPhase == CP_CONNECTING_TO_CHECKIP) if (connectPhase == CP_CONNECTING_TO_CHECKIP)
{ {
checkIpAddress=serverAddress; checkIpAddress=serverAddress;
connectPhase = CP_WAITING_FOR_CHECKIP_RESPONSE; connectPhase = CP_WAITING_FOR_CHECKIP_RESPONSE;
tcp->Send("GET\n\n", (unsigned int) strlen("GET\n\n"), serverAddress, false); // Needs 2 newlines! This is not documented and wasted a lot of my time tcp->Send("GET\n\n", (unsigned int) strlen("GET\n\n"), serverAddress, false); // Needs 2 newlines! This is not documented and wasted a lot of my time
} }
else else
{ {
connectPhase = CP_WAITING_FOR_DYNDNS_RESPONSE; connectPhase = CP_WAITING_FOR_DYNDNS_RESPONSE;
tcp->Send(getString.C_String(), (unsigned int) getString.GetLength(), serverAddress, false); tcp->Send(getString.C_String(), (unsigned int) getString.GetLength(), serverAddress, false);
} }
phaseTimeout=RakNet::GetTime()+1000; phaseTimeout=RakNet::GetTime()+1000;
} }
if (connectPhase==CP_WAITING_FOR_CHECKIP_RESPONSE && RakNet::GetTime()>phaseTimeout) if (connectPhase==CP_WAITING_FOR_CHECKIP_RESPONSE && RakNet::GetTime()>phaseTimeout)
{ {
connectPhase = CP_CONNECTING_TO_DYNDNS; connectPhase = CP_CONNECTING_TO_DYNDNS;
tcp->CloseConnection(checkIpAddress); tcp->CloseConnection(checkIpAddress);
tcp->Connect("members.dyndns.org", 80, false); tcp->Connect("members.dyndns.org", 80, false);
} }
else if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE && RakNet::GetTime()>phaseTimeout) else if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE && RakNet::GetTime()>phaseTimeout)
{ {
SetCompleted(RC_DYNDNS_TIMEOUT, "DynDNS did not respond"); SetCompleted(RC_DYNDNS_TIMEOUT, "DynDNS did not respond");
return; return;
} }
Packet *packet = tcp->Receive(); Packet *packet = tcp->Receive();
if (packet) if (packet)
{ {
if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE) if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE)
{ {
unsigned int i; unsigned int i;
char *result; char *result;
result=strstr((char*) packet->data, "Connection: close"); result=strstr((char*) packet->data, "Connection: close");
if (result!=0) if (result!=0)
{ {
result+=strlen("Connection: close"); result+=strlen("Connection: close");
while (*result && (*result=='\r') || (*result=='\n') || (*result==' ') ) while (*result && (*result=='\r') || (*result=='\n') || (*result==' ') )
result++; result++;
for (i=0; i < 13; i++) for (i=0; i < 13; i++)
{ {
if (strncmp(resultTable[i].code, result, strlen(resultTable[i].code))==0) if (strncmp(resultTable[i].code, result, strlen(resultTable[i].code))==0)
{ {
if (resultTable[i].resultCode==RC_SUCCESS) if (resultTable[i].resultCode==RC_SUCCESS)
{ {
// Read my external IP into myIPStr // Read my external IP into myIPStr
// Advance until we hit a number // Advance until we hit a number
while (*result && ((*result<'0') || (*result>'9')) ) while (*result && ((*result<'0') || (*result>'9')) )
result++; result++;
if (*result) if (*result)
{ {
SystemAddress parser; SystemAddress parser;
parser.FromString(result); parser.FromString(result);
parser.ToString(false, myIPStr); parser.ToString(false, myIPStr);
} }
} }
tcp->DeallocatePacket(packet); tcp->DeallocatePacket(packet);
SetCompleted(resultTable[i].resultCode, resultTable[i].description); SetCompleted(resultTable[i].resultCode, resultTable[i].description);
break; break;
} }
} }
if (i==13) if (i==13)
{ {
tcp->DeallocatePacket(packet); tcp->DeallocatePacket(packet);
SetCompleted(RC_UNKNOWN_RESULT, "DynDNS returned unknown result"); SetCompleted(RC_UNKNOWN_RESULT, "DynDNS returned unknown result");
} }
} }
else else
{ {
tcp->DeallocatePacket(packet); tcp->DeallocatePacket(packet);
SetCompleted(RC_PARSING_FAILURE, "Parsing failure on returned string from DynDNS"); SetCompleted(RC_PARSING_FAILURE, "Parsing failure on returned string from DynDNS");
} }
return; return;
} }
else else
{ {
/* /*
HTTP/1.1 200 OK HTTP/1.1 200 OK
Content-Type: text/html Content-Type: text/html
Server: DynDNS-CheckIP/1.0 Server: DynDNS-CheckIP/1.0
Connection: close Connection: close
Cache-Control: no-cache Cache-Control: no-cache
Pragma: no-cache Pragma: no-cache
Content-Length: 105 Content-Length: 105
<html><head><title>Current IP Check</title></head><body>Current IP Address: 98.1 <html><head><title>Current IP Check</title></head><body>Current IP Address: 98.1
89.219.22</body></html> 89.219.22</body></html>
Connection to host lost. Connection to host lost.
*/ */
char *result; char *result;
result=strstr((char*) packet->data, "Current IP Address: "); result=strstr((char*) packet->data, "Current IP Address: ");
if (result!=0) if (result!=0)
{ {
result+=strlen("Current IP Address: "); result+=strlen("Current IP Address: ");
SystemAddress myIp; SystemAddress myIp;
myIp.FromString(result); myIp.FromString(result);
myIp.ToString(false, myIPStr); myIp.ToString(false, myIPStr);
// Resolve DNS we are setting. If equal to current then abort // Resolve DNS we are setting. If equal to current then abort
const char *existingHost = ( char* ) SocketLayer::DomainNameToIP( host.C_String() ); const char *existingHost = ( char* ) SocketLayer::DomainNameToIP( host.C_String() );
if (existingHost && strcmp(existingHost, myIPStr)==0) if (existingHost && strcmp(existingHost, myIPStr)==0)
{ {
// DynDNS considers setting the IP to what it is already set abuse // DynDNS considers setting the IP to what it is already set abuse
tcp->DeallocatePacket(packet); tcp->DeallocatePacket(packet);
SetCompleted(RC_DNS_ALREADY_SET, "No action needed"); SetCompleted(RC_DNS_ALREADY_SET, "No action needed");
return; return;
} }
} }
tcp->DeallocatePacket(packet); tcp->DeallocatePacket(packet);
tcp->CloseConnection(packet->systemAddress); tcp->CloseConnection(packet->systemAddress);
connectPhase = CP_CONNECTING_TO_DYNDNS; connectPhase = CP_CONNECTING_TO_DYNDNS;
tcp->Connect("members.dyndns.org", 80, false); tcp->Connect("members.dyndns.org", 80, false);
} }
} }
if (tcp->HasLostConnection()!=UNASSIGNED_SYSTEM_ADDRESS) if (tcp->HasLostConnection()!=UNASSIGNED_SYSTEM_ADDRESS)
{ {
if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE) if (connectPhase==CP_WAITING_FOR_DYNDNS_RESPONSE)
{ {
SetCompleted(RC_CONNECTION_LOST_WITHOUT_RESPONSE, "Connection lost to DynDNS during GET operation"); SetCompleted(RC_CONNECTION_LOST_WITHOUT_RESPONSE, "Connection lost to DynDNS during GET operation");
} }
} }
} }
#endif // _RAKNET_SUPPORT_DynDNS #endif // _RAKNET_SUPPORT_DynDNS

View File

@@ -1,100 +1,100 @@
/// \file DynDNS.h /// \file DynDNS.h
/// \brief Helper to class to update DynDNS /// \brief Helper to class to update DynDNS
/// This can be used to determine what permissions are should be allowed to the other system /// This can be used to determine what permissions are should be allowed to the other system
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_DynDNS==1 && _RAKNET_SUPPORT_TCPInterface==1 #if _RAKNET_SUPPORT_DynDNS==1 && _RAKNET_SUPPORT_TCPInterface==1
class TCPInterface; class TCPInterface;
#ifndef __DYN_DNS_H #ifndef __DYN_DNS_H
#define __DYN_DNS_H #define __DYN_DNS_H
namespace RakNet namespace RakNet
{ {
enum DynDnsResultCode enum DynDnsResultCode
{ {
// ----- Success ----- // ----- Success -----
RC_SUCCESS, RC_SUCCESS,
RC_DNS_ALREADY_SET, // RakNet detects no action is needed RC_DNS_ALREADY_SET, // RakNet detects no action is needed
// ----- Ignorable failure (treat same as success) ----- // ----- Ignorable failure (treat same as success) -----
RC_NO_CHANGE, // DynDNS detects no action is needed (treated as abuse though) RC_NO_CHANGE, // DynDNS detects no action is needed (treated as abuse though)
// ----- User error ----- // ----- User error -----
RC_NOT_DONATOR, // You have to pay to do this RC_NOT_DONATOR, // You have to pay to do this
RC_NO_HOST, // This host does not exist at all RC_NO_HOST, // This host does not exist at all
RC_BAD_AUTH, // You set the wrong password RC_BAD_AUTH, // You set the wrong password
RC_NOT_YOURS, // This is not your host RC_NOT_YOURS, // This is not your host
// ----- Permanent failure ----- // ----- Permanent failure -----
RC_ABUSE, // Your host has been blocked, too many failures disable your account RC_ABUSE, // Your host has been blocked, too many failures disable your account
RC_TCP_FAILED_TO_START, // TCP port already in use RC_TCP_FAILED_TO_START, // TCP port already in use
RC_TCP_DID_NOT_CONNECT, // DynDNS down? RC_TCP_DID_NOT_CONNECT, // DynDNS down?
RC_UNKNOWN_RESULT, // DynDNS returned a result code that was not documented as of 12/4/2010 on http://www.dyndns.com/developers/specs/flow.pdf RC_UNKNOWN_RESULT, // DynDNS returned a result code that was not documented as of 12/4/2010 on http://www.dyndns.com/developers/specs/flow.pdf
RC_PARSING_FAILURE, // Can't read the result returned, format change? RC_PARSING_FAILURE, // Can't read the result returned, format change?
RC_CONNECTION_LOST_WITHOUT_RESPONSE, // Lost the connection to DynDNS while communicating RC_CONNECTION_LOST_WITHOUT_RESPONSE, // Lost the connection to DynDNS while communicating
RC_BAD_AGENT, // ??? RC_BAD_AGENT, // ???
RC_BAD_SYS, // ??? RC_BAD_SYS, // ???
RC_DNS_ERROR, // ??? RC_DNS_ERROR, // ???
RC_NOT_FQDN, // ??? RC_NOT_FQDN, // ???
RC_NUM_HOST, // ??? RC_NUM_HOST, // ???
RC_911, // ??? RC_911, // ???
RC_DYNDNS_TIMEOUT, // DynDNS did not respond RC_DYNDNS_TIMEOUT, // DynDNS did not respond
}; };
// Can only process one at a time with the current implementation // Can only process one at a time with the current implementation
class RAK_DLL_EXPORT DynDNS class RAK_DLL_EXPORT DynDNS
{ {
public: public:
DynDNS(); DynDNS();
~DynDNS(); ~DynDNS();
// Pass 0 for newIPAddress to autodetect whatever you are uploading from // Pass 0 for newIPAddress to autodetect whatever you are uploading from
// usernameAndPassword should be in the format username:password // usernameAndPassword should be in the format username:password
void UpdateHostIP(const char *dnsHost, const char *newIPAddress, const char *usernameAndPassword ); void UpdateHostIP(const char *dnsHost, const char *newIPAddress, const char *usernameAndPassword );
void Update(void); void Update(void);
// Output // Output
bool IsRunning(void) const {return connectPhase!=CP_IDLE;} bool IsRunning(void) const {return connectPhase!=CP_IDLE;}
bool IsCompleted(void) const {return connectPhase==CP_IDLE;} bool IsCompleted(void) const {return connectPhase==CP_IDLE;}
RakNet::DynDnsResultCode GetCompletedResultCode(void) {return result;} RakNet::DynDnsResultCode GetCompletedResultCode(void) {return result;}
const char *GetCompletedDescription(void) const {return resultDescription;} const char *GetCompletedDescription(void) const {return resultDescription;}
bool WasResultSuccessful(void) const {return result==RC_SUCCESS || result==RC_DNS_ALREADY_SET || result==RC_NO_CHANGE;} bool WasResultSuccessful(void) const {return result==RC_SUCCESS || result==RC_DNS_ALREADY_SET || result==RC_NO_CHANGE;}
char *GetMyPublicIP(void) const {return (char*) myIPStr;} // We get our public IP as part of the process. This is valid once completed char *GetMyPublicIP(void) const {return (char*) myIPStr;} // We get our public IP as part of the process. This is valid once completed
protected: protected:
void Stop(void); void Stop(void);
void SetCompleted(RakNet::DynDnsResultCode _result, const char *_resultDescription) {Stop(); result=_result; resultDescription=_resultDescription;} void SetCompleted(RakNet::DynDnsResultCode _result, const char *_resultDescription) {Stop(); result=_result; resultDescription=_resultDescription;}
enum ConnectPhase enum ConnectPhase
{ {
CP_CONNECTING_TO_CHECKIP, CP_CONNECTING_TO_CHECKIP,
CP_WAITING_FOR_CHECKIP_RESPONSE, CP_WAITING_FOR_CHECKIP_RESPONSE,
CP_CONNECTING_TO_DYNDNS, CP_CONNECTING_TO_DYNDNS,
CP_WAITING_FOR_DYNDNS_RESPONSE, CP_WAITING_FOR_DYNDNS_RESPONSE,
CP_IDLE, CP_IDLE,
}; };
TCPInterface *tcp; TCPInterface *tcp;
RakNet::RakString getString; RakNet::RakString getString;
SystemAddress serverAddress; SystemAddress serverAddress;
ConnectPhase connectPhase; ConnectPhase connectPhase;
RakNet::RakString host; RakNet::RakString host;
RakNet::Time phaseTimeout; RakNet::Time phaseTimeout;
SystemAddress checkIpAddress; SystemAddress checkIpAddress;
const char *resultDescription; const char *resultDescription;
RakNet::DynDnsResultCode result; RakNet::DynDnsResultCode result;
char myIPStr[32]; char myIPStr[32];
}; };
} // namespace RakNet } // namespace RakNet
#endif // __DYN_DNS_H #endif // __DYN_DNS_H
#endif // _RAKNET_SUPPORT_DynDNS #endif // _RAKNET_SUPPORT_DynDNS

View File

@@ -1,362 +1,362 @@
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_EmailSender==1 && _RAKNET_SUPPORT_TCPInterface==1 && _RAKNET_SUPPORT_FileOperations==1 #if _RAKNET_SUPPORT_EmailSender==1 && _RAKNET_SUPPORT_TCPInterface==1 && _RAKNET_SUPPORT_FileOperations==1
// Useful sites // Useful sites
// http://www.faqs.org\rfcs\rfc2821.html // http://www.faqs.org\rfcs\rfc2821.html
// http://www2.rad.com\networks/1995/mime/examples.htm // http://www2.rad.com\networks/1995/mime/examples.htm
#include "EmailSender.h" #include "EmailSender.h"
#include "TCPInterface.h" #include "TCPInterface.h"
#include "GetTime.h" #include "GetTime.h"
#include "Rand.h" #include "Rand.h"
#include "FileList.h" #include "FileList.h"
#include "BitStream.h" #include "BitStream.h"
#include <stdio.h> #include <stdio.h>
#include "RakSleep.h" #include "RakSleep.h"
using namespace RakNet; using namespace RakNet;
STATIC_FACTORY_DEFINITIONS(EmailSender,EmailSender); STATIC_FACTORY_DEFINITIONS(EmailSender,EmailSender);
const char *EmailSender::Send(const char *hostAddress, unsigned short hostPort, const char *sender, const char *recipient, const char *senderName, const char *recipientName, const char *subject, const char *body, FileList *attachedFiles, bool doPrintf, const char *password) const char *EmailSender::Send(const char *hostAddress, unsigned short hostPort, const char *sender, const char *recipient, const char *senderName, const char *recipientName, const char *subject, const char *body, FileList *attachedFiles, bool doPrintf, const char *password)
{ {
RakNet::Packet *packet; RakNet::Packet *packet;
char query[1024]; char query[1024];
TCPInterface tcpInterface; TCPInterface tcpInterface;
SystemAddress emailServer; SystemAddress emailServer;
if (tcpInterface.Start(0, 0)==false) if (tcpInterface.Start(0, 0)==false)
return "Unknown error starting TCP"; return "Unknown error starting TCP";
emailServer=tcpInterface.Connect(hostAddress, hostPort,true); emailServer=tcpInterface.Connect(hostAddress, hostPort,true);
if (emailServer==UNASSIGNED_SYSTEM_ADDRESS) if (emailServer==UNASSIGNED_SYSTEM_ADDRESS)
return "Failed to connect to host"; return "Failed to connect to host";
#if OPEN_SSL_CLIENT_SUPPORT==1 #if OPEN_SSL_CLIENT_SUPPORT==1
tcpInterface.StartSSLClient(emailServer); tcpInterface.StartSSLClient(emailServer);
#endif #endif
RakNet::TimeMS timeoutTime = RakNet::GetTimeMS()+3000; RakNet::TimeMS timeoutTime = RakNet::GetTimeMS()+3000;
packet=0; packet=0;
while (RakNet::GetTimeMS() < timeoutTime) while (RakNet::GetTimeMS() < timeoutTime)
{ {
packet = tcpInterface.Receive(); packet = tcpInterface.Receive();
if (packet) if (packet)
{ {
if (doPrintf) if (doPrintf)
RAKNET_DEBUG_PRINTF("%s", packet->data); RAKNET_DEBUG_PRINTF("%s", packet->data);
break; break;
} }
RakSleep(250); RakSleep(250);
} }
if (packet==0) if (packet==0)
return "Timeout while waiting for initial data from server."; return "Timeout while waiting for initial data from server.";
tcpInterface.Send("EHLO\r\n", 6, emailServer,false); tcpInterface.Send("EHLO\r\n", 6, emailServer,false);
const char *response; const char *response;
bool authenticate=false; bool authenticate=false;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(disable:4127) // conditional expression is constant #pragma warning(disable:4127) // conditional expression is constant
#endif #endif
while (1) while (1)
{ {
response=GetResponse(&tcpInterface, emailServer, doPrintf); response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0 && strcmp(response, "AUTHENTICATE")==0) if (response!=0 && strcmp(response, "AUTHENTICATE")==0)
{ {
authenticate=true; authenticate=true;
break; break;
} }
// Something other than continue? // Something other than continue?
if (response!=0 && strcmp(response, "CONTINUE")!=0) if (response!=0 && strcmp(response, "CONTINUE")!=0)
return response; return response;
// Success? // Success?
if (response==0) if (response==0)
break; break;
} }
if (authenticate) if (authenticate)
{ {
sprintf(query, "EHLO %s\r\n", sender); sprintf(query, "EHLO %s\r\n", sender);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
response=GetResponse(&tcpInterface, emailServer, doPrintf); response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0) if (response!=0)
return response; return response;
if (password==0) if (password==0)
return "Password needed"; return "Password needed";
char *outputData = RakNet::OP_NEW_ARRAY<char >((const int) (strlen(sender)+strlen(password)+2)*3, _FILE_AND_LINE_ ); char *outputData = RakNet::OP_NEW_ARRAY<char >((const int) (strlen(sender)+strlen(password)+2)*3, _FILE_AND_LINE_ );
RakNet::BitStream bs; RakNet::BitStream bs;
char zero=0; char zero=0;
bs.Write(&zero,1); bs.Write(&zero,1);
bs.Write(sender,(const unsigned int)strlen(sender)); bs.Write(sender,(const unsigned int)strlen(sender));
//bs.Write("jms1@jms1.net",(const unsigned int)strlen("jms1@jms1.net")); //bs.Write("jms1@jms1.net",(const unsigned int)strlen("jms1@jms1.net"));
bs.Write(&zero,1); bs.Write(&zero,1);
bs.Write(password,(const unsigned int)strlen(password)); bs.Write(password,(const unsigned int)strlen(password));
bs.Write(&zero,1); bs.Write(&zero,1);
//bs.Write("not.my.real.password",(const unsigned int)strlen("not.my.real.password")); //bs.Write("not.my.real.password",(const unsigned int)strlen("not.my.real.password"));
TCPInterface::Base64Encoding((const char*)bs.GetData(), bs.GetNumberOfBytesUsed(), outputData); TCPInterface::Base64Encoding((const char*)bs.GetData(), bs.GetNumberOfBytesUsed(), outputData);
sprintf(query, "AUTH PLAIN %s", outputData); sprintf(query, "AUTH PLAIN %s", outputData);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
response=GetResponse(&tcpInterface, emailServer, doPrintf); response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0) if (response!=0)
return response; return response;
} }
if (sender) if (sender)
sprintf(query, "MAIL From: <%s>\r\n", sender); sprintf(query, "MAIL From: <%s>\r\n", sender);
else else
sprintf(query, "MAIL From: <>\r\n"); sprintf(query, "MAIL From: <>\r\n");
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
response=GetResponse(&tcpInterface, emailServer, doPrintf); response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0) if (response!=0)
return response; return response;
if (recipient) if (recipient)
sprintf(query, "RCPT TO: <%s>\r\n", recipient); sprintf(query, "RCPT TO: <%s>\r\n", recipient);
else else
sprintf(query, "RCPT TO: <>\r\n"); sprintf(query, "RCPT TO: <>\r\n");
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
response=GetResponse(&tcpInterface, emailServer, doPrintf); response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0) if (response!=0)
return response; return response;
tcpInterface.Send("DATA\r\n", (unsigned int)strlen("DATA\r\n"), emailServer,false); tcpInterface.Send("DATA\r\n", (unsigned int)strlen("DATA\r\n"), emailServer,false);
// Wait for 354... // Wait for 354...
response=GetResponse(&tcpInterface, emailServer, doPrintf); response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0) if (response!=0)
return response; return response;
if (subject) if (subject)
{ {
sprintf(query, "Subject: %s\r\n", subject); sprintf(query, "Subject: %s\r\n", subject);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
} }
if (senderName) if (senderName)
{ {
sprintf(query, "From: %s\r\n", senderName); sprintf(query, "From: %s\r\n", senderName);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
} }
if (recipientName) if (recipientName)
{ {
sprintf(query, "To: %s\r\n", recipientName); sprintf(query, "To: %s\r\n", recipientName);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
} }
const int boundarySize=60; const int boundarySize=60;
char boundary[boundarySize+1]; char boundary[boundarySize+1];
int i,j; int i,j;
if (attachedFiles && attachedFiles->fileList.Size()) if (attachedFiles && attachedFiles->fileList.Size())
{ {
rakNetRandom.SeedMT((unsigned int) RakNet::GetTimeMS()); rakNetRandom.SeedMT((unsigned int) RakNet::GetTimeMS());
// Random multipart message boundary // Random multipart message boundary
for (i=0; i < boundarySize; i++) for (i=0; i < boundarySize; i++)
boundary[i]=TCPInterface::Base64Map()[rakNetRandom.RandomMT()%64]; boundary[i]=TCPInterface::Base64Map()[rakNetRandom.RandomMT()%64];
boundary[boundarySize]=0; boundary[boundarySize]=0;
} }
sprintf(query, "MIME-version: 1.0\r\n"); sprintf(query, "MIME-version: 1.0\r\n");
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
if (attachedFiles && attachedFiles->fileList.Size()) if (attachedFiles && attachedFiles->fileList.Size())
{ {
sprintf(query, "Content-type: multipart/mixed; BOUNDARY=\"%s\"\r\n\r\n", boundary); sprintf(query, "Content-type: multipart/mixed; BOUNDARY=\"%s\"\r\n\r\n", boundary);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
sprintf(query, "This is a multi-part message in MIME format.\r\n\r\n--%s\r\n", boundary); sprintf(query, "This is a multi-part message in MIME format.\r\n\r\n--%s\r\n", boundary);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
} }
sprintf(query, "Content-Type: text/plain; charset=\"US-ASCII\"\r\n\r\n"); sprintf(query, "Content-Type: text/plain; charset=\"US-ASCII\"\r\n\r\n");
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
// Write the body of the email, doing some lame shitty shit where I have to make periods at the start of a newline have a second period. // Write the body of the email, doing some lame shitty shit where I have to make periods at the start of a newline have a second period.
char *newBody; char *newBody;
int bodyLength; int bodyLength;
bodyLength=(int)strlen(body); bodyLength=(int)strlen(body);
newBody = (char*) rakMalloc_Ex( bodyLength*3, _FILE_AND_LINE_ ); newBody = (char*) rakMalloc_Ex( bodyLength*3, _FILE_AND_LINE_ );
if (bodyLength>0) if (bodyLength>0)
newBody[0]=body[0]; newBody[0]=body[0];
for (i=1, j=1; i < bodyLength; i++) for (i=1, j=1; i < bodyLength; i++)
{ {
// Transform \n . \r \n into \n . . \r \n // Transform \n . \r \n into \n . . \r \n
if (i < bodyLength-2 && if (i < bodyLength-2 &&
body[i-1]=='\n' && body[i-1]=='\n' &&
body[i+0]=='.' && body[i+0]=='.' &&
body[i+1]=='\r' && body[i+1]=='\r' &&
body[i+2]=='\n') body[i+2]=='\n')
{ {
newBody[j++]='.'; newBody[j++]='.';
newBody[j++]='.'; newBody[j++]='.';
newBody[j++]='\r'; newBody[j++]='\r';
newBody[j++]='\n'; newBody[j++]='\n';
i+=2; i+=2;
} }
// Transform \n . . \r \n into \n . . . \r \n // Transform \n . . \r \n into \n . . . \r \n
// Having to process .. is a bug in the mail server - the spec says ONLY \r\n.\r\n should be transformed // Having to process .. is a bug in the mail server - the spec says ONLY \r\n.\r\n should be transformed
else if (i <= bodyLength-3 && else if (i <= bodyLength-3 &&
body[i-1]=='\n' && body[i-1]=='\n' &&
body[i+0]=='.' && body[i+0]=='.' &&
body[i+1]=='.' && body[i+1]=='.' &&
body[i+2]=='\r' && body[i+2]=='\r' &&
body[i+3]=='\n') body[i+3]=='\n')
{ {
newBody[j++]='.'; newBody[j++]='.';
newBody[j++]='.'; newBody[j++]='.';
newBody[j++]='.'; newBody[j++]='.';
newBody[j++]='\r'; newBody[j++]='\r';
newBody[j++]='\n'; newBody[j++]='\n';
i+=3; i+=3;
} }
// Transform \n . \n into \n . . \r \n (this is a bug in the mail server - the spec says do not count \n alone but it does) // Transform \n . \n into \n . . \r \n (this is a bug in the mail server - the spec says do not count \n alone but it does)
else if (i < bodyLength-1 && else if (i < bodyLength-1 &&
body[i-1]=='\n' && body[i-1]=='\n' &&
body[i+0]=='.' && body[i+0]=='.' &&
body[i+1]=='\n') body[i+1]=='\n')
{ {
newBody[j++]='.'; newBody[j++]='.';
newBody[j++]='.'; newBody[j++]='.';
newBody[j++]='\r'; newBody[j++]='\r';
newBody[j++]='\n'; newBody[j++]='\n';
i+=1; i+=1;
} }
// Transform \n . . \n into \n . . . \r \n (this is a bug in the mail server - the spec says do not count \n alone but it does) // Transform \n . . \n into \n . . . \r \n (this is a bug in the mail server - the spec says do not count \n alone but it does)
// In fact having to process .. is a bug too - because the spec says ONLY \r\n.\r\n should be transformed // In fact having to process .. is a bug too - because the spec says ONLY \r\n.\r\n should be transformed
else if (i <= bodyLength-2 && else if (i <= bodyLength-2 &&
body[i-1]=='\n' && body[i-1]=='\n' &&
body[i+0]=='.' && body[i+0]=='.' &&
body[i+1]=='.' && body[i+1]=='.' &&
body[i+2]=='\n') body[i+2]=='\n')
{ {
newBody[j++]='.'; newBody[j++]='.';
newBody[j++]='.'; newBody[j++]='.';
newBody[j++]='.'; newBody[j++]='.';
newBody[j++]='\r'; newBody[j++]='\r';
newBody[j++]='\n'; newBody[j++]='\n';
i+=2; i+=2;
} }
else else
newBody[j++]=body[i]; newBody[j++]=body[i];
} }
newBody[j++]='\r'; newBody[j++]='\r';
newBody[j++]='\n'; newBody[j++]='\n';
tcpInterface.Send(newBody, j, emailServer,false); tcpInterface.Send(newBody, j, emailServer,false);
rakFree_Ex(newBody, _FILE_AND_LINE_ ); rakFree_Ex(newBody, _FILE_AND_LINE_ );
int outputOffset; int outputOffset;
// What a pain in the rear. I have to map the binary to printable characters using 6 bits per character. // What a pain in the rear. I have to map the binary to printable characters using 6 bits per character.
if (attachedFiles && attachedFiles->fileList.Size()) if (attachedFiles && attachedFiles->fileList.Size())
{ {
for (i=0; i < (int) attachedFiles->fileList.Size(); i++) for (i=0; i < (int) attachedFiles->fileList.Size(); i++)
{ {
// Write boundary // Write boundary
sprintf(query, "\r\n--%s\r\n", boundary); sprintf(query, "\r\n--%s\r\n", boundary);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
sprintf(query, "Content-Type: APPLICATION/Octet-Stream; SizeOnDisk=%i; name=\"%s\"\r\nContent-Transfer-Encoding: BASE64\r\nContent-Description: %s\r\n\r\n", attachedFiles->fileList[i].dataLengthBytes, attachedFiles->fileList[i].filename.C_String(), attachedFiles->fileList[i].filename.C_String()); sprintf(query, "Content-Type: APPLICATION/Octet-Stream; SizeOnDisk=%i; name=\"%s\"\r\nContent-Transfer-Encoding: BASE64\r\nContent-Description: %s\r\n\r\n", attachedFiles->fileList[i].dataLengthBytes, attachedFiles->fileList[i].filename.C_String(), attachedFiles->fileList[i].filename.C_String());
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
newBody = (char*) rakMalloc_Ex( (size_t) (attachedFiles->fileList[i].dataLengthBytes*3)/2, _FILE_AND_LINE_ ); newBody = (char*) rakMalloc_Ex( (size_t) (attachedFiles->fileList[i].dataLengthBytes*3)/2, _FILE_AND_LINE_ );
outputOffset=TCPInterface::Base64Encoding(attachedFiles->fileList[i].data, (int) attachedFiles->fileList[i].dataLengthBytes, newBody); outputOffset=TCPInterface::Base64Encoding(attachedFiles->fileList[i].data, (int) attachedFiles->fileList[i].dataLengthBytes, newBody);
// Send the base64 mapped file. // Send the base64 mapped file.
tcpInterface.Send(newBody, outputOffset, emailServer,false); tcpInterface.Send(newBody, outputOffset, emailServer,false);
rakFree_Ex(newBody, _FILE_AND_LINE_ ); rakFree_Ex(newBody, _FILE_AND_LINE_ );
} }
// Write last boundary // Write last boundary
sprintf(query, "\r\n--%s--\r\n", boundary); sprintf(query, "\r\n--%s--\r\n", boundary);
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
} }
sprintf(query, "\r\n.\r\n"); sprintf(query, "\r\n.\r\n");
tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false); tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
response=GetResponse(&tcpInterface, emailServer, doPrintf); response=GetResponse(&tcpInterface, emailServer, doPrintf);
if (response!=0) if (response!=0)
return response; return response;
tcpInterface.Send("QUIT\r\n", (unsigned int)strlen("QUIT\r\n"), emailServer,false); tcpInterface.Send("QUIT\r\n", (unsigned int)strlen("QUIT\r\n"), emailServer,false);
RakSleep(30); RakSleep(30);
if (doPrintf) if (doPrintf)
{ {
packet = tcpInterface.Receive(); packet = tcpInterface.Receive();
while (packet) while (packet)
{ {
RAKNET_DEBUG_PRINTF("%s", packet->data); RAKNET_DEBUG_PRINTF("%s", packet->data);
packet = tcpInterface.Receive(); packet = tcpInterface.Receive();
} }
} }
tcpInterface.Stop(); tcpInterface.Stop();
return 0; // Success return 0; // Success
} }
const char *EmailSender::GetResponse(TCPInterface *tcpInterface, const SystemAddress &emailServer, bool doPrintf) const char *EmailSender::GetResponse(TCPInterface *tcpInterface, const SystemAddress &emailServer, bool doPrintf)
{ {
RakNet::Packet *packet; RakNet::Packet *packet;
RakNet::TimeMS timeout; RakNet::TimeMS timeout;
timeout=RakNet::GetTimeMS()+5000; timeout=RakNet::GetTimeMS()+5000;
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif #endif
while (1) while (1)
{ {
if (tcpInterface->HasLostConnection()==emailServer) if (tcpInterface->HasLostConnection()==emailServer)
return "Connection to server lost."; return "Connection to server lost.";
packet = tcpInterface->Receive(); packet = tcpInterface->Receive();
if (packet) if (packet)
{ {
if (doPrintf) if (doPrintf)
{ {
RAKNET_DEBUG_PRINTF("%s", packet->data); RAKNET_DEBUG_PRINTF("%s", packet->data);
} }
#if OPEN_SSL_CLIENT_SUPPORT==1 #if OPEN_SSL_CLIENT_SUPPORT==1
if (strstr((const char*)packet->data, "220")) if (strstr((const char*)packet->data, "220"))
{ {
tcpInterface->StartSSLClient(packet->systemAddress); tcpInterface->StartSSLClient(packet->systemAddress);
return "AUTHENTICATE"; // OK return "AUTHENTICATE"; // OK
} }
// if (strstr((const char*)packet->data, "250-AUTH LOGIN PLAIN")) // if (strstr((const char*)packet->data, "250-AUTH LOGIN PLAIN"))
// { // {
// tcpInterface->StartSSLClient(packet->systemAddress); // tcpInterface->StartSSLClient(packet->systemAddress);
// return "AUTHENTICATE"; // OK // return "AUTHENTICATE"; // OK
// } // }
#endif #endif
if (strstr((const char*)packet->data, "235")) if (strstr((const char*)packet->data, "235"))
return 0; // Authentication accepted return 0; // Authentication accepted
if (strstr((const char*)packet->data, "354")) if (strstr((const char*)packet->data, "354"))
return 0; // Go ahead return 0; // Go ahead
#if OPEN_SSL_CLIENT_SUPPORT==1 #if OPEN_SSL_CLIENT_SUPPORT==1
if (strstr((const char*)packet->data, "250-STARTTLS")) if (strstr((const char*)packet->data, "250-STARTTLS"))
{ {
tcpInterface->Send("STARTTLS\r\n", (unsigned int) strlen("STARTTLS\r\n"), packet->systemAddress, false); tcpInterface->Send("STARTTLS\r\n", (unsigned int) strlen("STARTTLS\r\n"), packet->systemAddress, false);
return "CONTINUE"; return "CONTINUE";
} }
#endif #endif
if (strstr((const char*)packet->data, "250")) if (strstr((const char*)packet->data, "250"))
return 0; // OK return 0; // OK
if (strstr((const char*)packet->data, "550")) if (strstr((const char*)packet->data, "550"))
return "Failed on error code 550"; return "Failed on error code 550";
if (strstr((const char*)packet->data, "553")) if (strstr((const char*)packet->data, "553"))
return "Failed on error code 553"; return "Failed on error code 553";
} }
if (RakNet::GetTimeMS() > timeout) if (RakNet::GetTimeMS() > timeout)
return "Timed out"; return "Timed out";
RakSleep(100); RakSleep(100);
} }
} }
#endif // _RAKNET_SUPPORT_* #endif // _RAKNET_SUPPORT_*

View File

@@ -1,58 +1,58 @@
/// \file EmailSender.h /// \file EmailSender.h
/// \brief Rudimentary class to send email from code. Don't expect anything fancy. /// \brief Rudimentary class to send email from code. Don't expect anything fancy.
/// ///
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
/// ///
/// Usage of RakNet is subject to the appropriate license agreement. /// Usage of RakNet is subject to the appropriate license agreement.
#include "NativeFeatureIncludes.h" #include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_EmailSender==1 && _RAKNET_SUPPORT_TCPInterface==1 && _RAKNET_SUPPORT_FileOperations==1 #if _RAKNET_SUPPORT_EmailSender==1 && _RAKNET_SUPPORT_TCPInterface==1 && _RAKNET_SUPPORT_FileOperations==1
#ifndef __EMAIL_SENDER_H #ifndef __EMAIL_SENDER_H
#define __EMAIL_SENDER_H #define __EMAIL_SENDER_H
#include "RakNetTypes.h" #include "RakNetTypes.h"
#include "RakMemoryOverride.h" #include "RakMemoryOverride.h"
#include "Export.h" #include "Export.h"
#include "Rand.h" #include "Rand.h"
#include "TCPInterface.h" #include "TCPInterface.h"
namespace RakNet namespace RakNet
{ {
/// Forward declarations /// Forward declarations
class FileList; class FileList;
class TCPInterface; class TCPInterface;
/// \brief Rudimentary class to send email from code. /// \brief Rudimentary class to send email from code.
class RAK_DLL_EXPORT EmailSender class RAK_DLL_EXPORT EmailSender
{ {
public: public:
// GetInstance() and DestroyInstance(instance*) // GetInstance() and DestroyInstance(instance*)
STATIC_FACTORY_DECLARATIONS(EmailSender) STATIC_FACTORY_DECLARATIONS(EmailSender)
/// \brief Sends an email. /// \brief Sends an email.
/// \param[in] hostAddress The address of the email server. /// \param[in] hostAddress The address of the email server.
/// \param[in] hostPort The port of the email server (usually 25) /// \param[in] hostPort The port of the email server (usually 25)
/// \param[in] sender The email address you are sending from. /// \param[in] sender The email address you are sending from.
/// \param[in] recipient The email address you are sending to. /// \param[in] recipient The email address you are sending to.
/// \param[in] senderName The email address you claim to be sending from /// \param[in] senderName The email address you claim to be sending from
/// \param[in] recipientName The email address you claim to be sending to /// \param[in] recipientName The email address you claim to be sending to
/// \param[in] subject Email subject /// \param[in] subject Email subject
/// \param[in] body Email body /// \param[in] body Email body
/// \param[in] attachedFiles List of files to attach to the email. (Can be 0 to send none). /// \param[in] attachedFiles List of files to attach to the email. (Can be 0 to send none).
/// \param[in] doPrintf true to output SMTP info to console(for debugging?) /// \param[in] doPrintf true to output SMTP info to console(for debugging?)
/// \param[in] password Used if the server uses AUTHENTICATE PLAIN over TLS (such as gmail) /// \param[in] password Used if the server uses AUTHENTICATE PLAIN over TLS (such as gmail)
/// \return 0 on success, otherwise a string indicating the error message /// \return 0 on success, otherwise a string indicating the error message
const char *Send(const char *hostAddress, unsigned short hostPort, const char *sender, const char *recipient, const char *senderName, const char *recipientName, const char *subject, const char *body, FileList *attachedFiles, bool doPrintf, const char *password); const char *Send(const char *hostAddress, unsigned short hostPort, const char *sender, const char *recipient, const char *senderName, const char *recipientName, const char *subject, const char *body, FileList *attachedFiles, bool doPrintf, const char *password);
protected: protected:
const char *GetResponse(TCPInterface *tcpInterface, const SystemAddress &emailServer, bool doPrintf); const char *GetResponse(TCPInterface *tcpInterface, const SystemAddress &emailServer, bool doPrintf);
RakNetRandom rakNetRandom; RakNetRandom rakNetRandom;
}; };
} // namespace RakNet } // namespace RakNet
#endif #endif
#endif // _RAKNET_SUPPORT_* #endif // _RAKNET_SUPPORT_*

Some files were not shown because too many files have changed in this diff Show More