diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml new file mode 100644 index 000000000..14ba5547e --- /dev/null +++ b/AppImageBuilder.yml @@ -0,0 +1,51 @@ +version: 1 + +AppDir: + path: ./AppDir + + app_info: + id: minetest + name: Minetest + icon: minetest + version: !ENV ${VERSION} + exec: usr/bin/minetest + exec_args: $@ + runtime: + env: + APPDIR_LIBRARY_PATH: $APPDIR/usr/lib/x86_64-linux-gnu + + apt: + arch: amd64 + sources: + - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic main universe + key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' + - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-updates main universe + - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-backports main universe + - sourceline: deb http://archive.ubuntu.com/ubuntu/ bionic-security main universe + + include: + - libirrlicht1.8 + - libxxf86vm1 + - libgl1-mesa-glx + - libsqlite3-0 + - libogg0 + - libvorbis0a + - libopenal1 + - libcurl3-gnutls + - libfreetype6 + - zlib1g + - libgmp10 + - libjsoncpp1 + + files: + exclude: + - usr/share/man + - usr/share/doc/*/README.* + - usr/share/doc/*/changelog.* + - usr/share/doc/*/NEWS.* + - usr/share/doc/*/TODO.* + +AppImage: + update-information: None + sign-key: None + arch: x86_64 diff --git a/automt b/automt new file mode 100644 index 000000000..f406dae60 --- /dev/null +++ b/automt @@ -0,0 +1 @@ +waspsaliva \ No newline at end of file diff --git a/clammt b/clammt new file mode 100644 index 000000000..423ae0f73 --- /dev/null +++ b/clammt @@ -0,0 +1,7 @@ +#!/bin/sh +pwf=$HOME/.mtpw +if [ -z $1 ]; then echo "usage: clammt altname - (common) password must be in $pwf"; exit 1; fi +mt=$(dirname $0)/automt +pw=$(cat $pwf) +$mt clam-ity.minecity.online $1 $pw + diff --git a/textures/base/pack/air.png b/textures/base/pack/air.png new file mode 100644 index 000000000..e2c487214 Binary files /dev/null and b/textures/base/pack/air.png differ diff --git a/textures/base/pack/aux_btn.png b/textures/base/pack/aux_btn.png new file mode 100644 index 000000000..f589910e8 Binary files /dev/null and b/textures/base/pack/aux_btn.png differ diff --git a/textures/base/pack/blank.png b/textures/base/pack/blank.png new file mode 100644 index 000000000..85e02501d Binary files /dev/null and b/textures/base/pack/blank.png differ diff --git a/textures/base/pack/bubble.png b/textures/base/pack/bubble.png new file mode 100644 index 000000000..799327c61 Binary files /dev/null and b/textures/base/pack/bubble.png differ diff --git a/textures/base/pack/bubble_gone.png b/textures/base/pack/bubble_gone.png new file mode 100644 index 000000000..240ca4f8d Binary files /dev/null and b/textures/base/pack/bubble_gone.png differ diff --git a/textures/base/pack/camera_btn.png b/textures/base/pack/camera_btn.png new file mode 100644 index 000000000..9327dc4a6 Binary files /dev/null and b/textures/base/pack/camera_btn.png differ diff --git a/textures/base/pack/chat_btn.png b/textures/base/pack/chat_btn.png new file mode 100644 index 000000000..be4477d3e Binary files /dev/null and b/textures/base/pack/chat_btn.png differ diff --git a/textures/base/pack/chat_hide_btn.png b/textures/base/pack/chat_hide_btn.png new file mode 100644 index 000000000..92a8ece47 Binary files /dev/null and b/textures/base/pack/chat_hide_btn.png differ diff --git a/textures/base/pack/chat_show_btn.png b/textures/base/pack/chat_show_btn.png new file mode 100644 index 000000000..b260d2523 Binary files /dev/null and b/textures/base/pack/chat_show_btn.png differ diff --git a/textures/base/pack/checkbox_16.png b/textures/base/pack/checkbox_16.png new file mode 100644 index 000000000..db6101f36 Binary files /dev/null and b/textures/base/pack/checkbox_16.png differ diff --git a/textures/base/pack/checkbox_32.png b/textures/base/pack/checkbox_32.png new file mode 100644 index 000000000..f5ff59a3a Binary files /dev/null and b/textures/base/pack/checkbox_32.png differ diff --git a/textures/base/pack/checkbox_64.png b/textures/base/pack/checkbox_64.png new file mode 100644 index 000000000..03eb90bfe Binary files /dev/null and b/textures/base/pack/checkbox_64.png differ diff --git a/textures/base/pack/crack_anylength.png b/textures/base/pack/crack_anylength.png new file mode 100644 index 000000000..d9b49f911 Binary files /dev/null and b/textures/base/pack/crack_anylength.png differ diff --git a/textures/base/pack/debug_btn.png b/textures/base/pack/debug_btn.png new file mode 100644 index 000000000..ab210a6a4 Binary files /dev/null and b/textures/base/pack/debug_btn.png differ diff --git a/textures/base/pack/down.png b/textures/base/pack/down.png new file mode 100644 index 000000000..c290d3a45 Binary files /dev/null and b/textures/base/pack/down.png differ diff --git a/textures/base/pack/drop_btn.png b/textures/base/pack/drop_btn.png new file mode 100644 index 000000000..4403ce67b Binary files /dev/null and b/textures/base/pack/drop_btn.png differ diff --git a/textures/base/pack/end_icon.png b/textures/base/pack/end_icon.png new file mode 100644 index 000000000..4fb4d52a0 Binary files /dev/null and b/textures/base/pack/end_icon.png differ diff --git a/textures/base/pack/error_screenshot.png b/textures/base/pack/error_screenshot.png new file mode 100644 index 000000000..e35a0a38a Binary files /dev/null and b/textures/base/pack/error_screenshot.png differ diff --git a/textures/base/pack/fast_btn.png b/textures/base/pack/fast_btn.png new file mode 100644 index 000000000..aeb4d3c0c Binary files /dev/null and b/textures/base/pack/fast_btn.png differ diff --git a/textures/base/pack/fly_btn.png b/textures/base/pack/fly_btn.png new file mode 100644 index 000000000..641d0fa6e Binary files /dev/null and b/textures/base/pack/fly_btn.png differ diff --git a/textures/base/pack/gear_icon.png b/textures/base/pack/gear_icon.png new file mode 100644 index 000000000..520e82e1d Binary files /dev/null and b/textures/base/pack/gear_icon.png differ diff --git a/textures/base/pack/halo.png b/textures/base/pack/halo.png new file mode 100644 index 000000000..ed3ff9d8c Binary files /dev/null and b/textures/base/pack/halo.png differ diff --git a/textures/base/pack/heart.png b/textures/base/pack/heart.png new file mode 100644 index 000000000..13db59be4 Binary files /dev/null and b/textures/base/pack/heart.png differ diff --git a/textures/base/pack/heart_gone.png b/textures/base/pack/heart_gone.png new file mode 100644 index 000000000..240ca4f8d Binary files /dev/null and b/textures/base/pack/heart_gone.png differ diff --git a/textures/base/pack/ignore.png b/textures/base/pack/ignore.png new file mode 100644 index 000000000..a73d2222d Binary files /dev/null and b/textures/base/pack/ignore.png differ diff --git a/textures/base/pack/inventory_btn.png b/textures/base/pack/inventory_btn.png new file mode 100644 index 000000000..278ce39c7 Binary files /dev/null and b/textures/base/pack/inventory_btn.png differ diff --git a/textures/base/pack/joystick_bg.png b/textures/base/pack/joystick_bg.png new file mode 100644 index 000000000..406193998 Binary files /dev/null and b/textures/base/pack/joystick_bg.png differ diff --git a/textures/base/pack/joystick_center.png b/textures/base/pack/joystick_center.png new file mode 100644 index 000000000..1e4754d24 Binary files /dev/null and b/textures/base/pack/joystick_center.png differ diff --git a/textures/base/pack/joystick_off.png b/textures/base/pack/joystick_off.png new file mode 100644 index 000000000..6dfbc7a46 Binary files /dev/null and b/textures/base/pack/joystick_off.png differ diff --git a/textures/base/pack/jump_btn.png b/textures/base/pack/jump_btn.png new file mode 100644 index 000000000..d21b4a9f8 Binary files /dev/null and b/textures/base/pack/jump_btn.png differ diff --git a/textures/base/pack/loading_screenshot.png b/textures/base/pack/loading_screenshot.png new file mode 100644 index 000000000..4d65a5d8d Binary files /dev/null and b/textures/base/pack/loading_screenshot.png differ diff --git a/textures/base/pack/logo.png b/textures/base/pack/logo.png new file mode 100644 index 000000000..48793678f Binary files /dev/null and b/textures/base/pack/logo.png differ diff --git a/textures/base/pack/menu_bg.png b/textures/base/pack/menu_bg.png new file mode 100644 index 000000000..256d57c4a Binary files /dev/null and b/textures/base/pack/menu_bg.png differ diff --git a/textures/base/pack/menu_header.png b/textures/base/pack/menu_header.png new file mode 100644 index 000000000..1bfd61f99 Binary files /dev/null and b/textures/base/pack/menu_header.png differ diff --git a/textures/base/pack/minimap_btn.png b/textures/base/pack/minimap_btn.png new file mode 100644 index 000000000..727ba1e9d Binary files /dev/null and b/textures/base/pack/minimap_btn.png differ diff --git a/textures/base/pack/minimap_mask_round.png b/textures/base/pack/minimap_mask_round.png new file mode 100644 index 000000000..a0c6b2ddf Binary files /dev/null and b/textures/base/pack/minimap_mask_round.png differ diff --git a/textures/base/pack/minimap_mask_square.png b/textures/base/pack/minimap_mask_square.png new file mode 100644 index 000000000..160b6faff Binary files /dev/null and b/textures/base/pack/minimap_mask_square.png differ diff --git a/textures/base/pack/minimap_overlay_round.png b/textures/base/pack/minimap_overlay_round.png new file mode 100644 index 000000000..16e3c41c7 Binary files /dev/null and b/textures/base/pack/minimap_overlay_round.png differ diff --git a/textures/base/pack/minimap_overlay_square.png b/textures/base/pack/minimap_overlay_square.png new file mode 100644 index 000000000..c971c4b8e Binary files /dev/null and b/textures/base/pack/minimap_overlay_square.png differ diff --git a/textures/base/pack/next_icon.png b/textures/base/pack/next_icon.png new file mode 100644 index 000000000..03f960917 Binary files /dev/null and b/textures/base/pack/next_icon.png differ diff --git a/textures/base/pack/no_screenshot.png b/textures/base/pack/no_screenshot.png new file mode 100644 index 000000000..8c7089897 Binary files /dev/null and b/textures/base/pack/no_screenshot.png differ diff --git a/textures/base/pack/no_texture_airlike.png b/textures/base/pack/no_texture_airlike.png new file mode 100644 index 000000000..634ee8ca5 Binary files /dev/null and b/textures/base/pack/no_texture_airlike.png differ diff --git a/textures/base/pack/noclip_btn.png b/textures/base/pack/noclip_btn.png new file mode 100644 index 000000000..5d7372de5 Binary files /dev/null and b/textures/base/pack/noclip_btn.png differ diff --git a/textures/base/pack/object_marker_red.png b/textures/base/pack/object_marker_red.png new file mode 100644 index 000000000..f345d0376 Binary files /dev/null and b/textures/base/pack/object_marker_red.png differ diff --git a/textures/base/pack/player.png b/textures/base/pack/player.png new file mode 100644 index 000000000..6d61c4342 Binary files /dev/null and b/textures/base/pack/player.png differ diff --git a/textures/base/pack/player_back.png b/textures/base/pack/player_back.png new file mode 100644 index 000000000..5e9ef0542 Binary files /dev/null and b/textures/base/pack/player_back.png differ diff --git a/textures/base/pack/player_marker.png b/textures/base/pack/player_marker.png new file mode 100644 index 000000000..f2cc2c6f0 Binary files /dev/null and b/textures/base/pack/player_marker.png differ diff --git a/textures/base/pack/plus.png b/textures/base/pack/plus.png new file mode 100644 index 000000000..64680b569 Binary files /dev/null and b/textures/base/pack/plus.png differ diff --git a/textures/base/pack/prev_icon.png b/textures/base/pack/prev_icon.png new file mode 100644 index 000000000..71509e71a Binary files /dev/null and b/textures/base/pack/prev_icon.png differ diff --git a/textures/base/pack/progress_bar.png b/textures/base/pack/progress_bar.png new file mode 100644 index 000000000..e80367191 Binary files /dev/null and b/textures/base/pack/progress_bar.png differ diff --git a/textures/base/pack/progress_bar_bg.png b/textures/base/pack/progress_bar_bg.png new file mode 100644 index 000000000..4e30ae889 Binary files /dev/null and b/textures/base/pack/progress_bar_bg.png differ diff --git a/textures/base/pack/rangeview_btn.png b/textures/base/pack/rangeview_btn.png new file mode 100644 index 000000000..e49a1b636 Binary files /dev/null and b/textures/base/pack/rangeview_btn.png differ diff --git a/textures/base/pack/rare_controls.png b/textures/base/pack/rare_controls.png new file mode 100644 index 000000000..953d9e06d Binary files /dev/null and b/textures/base/pack/rare_controls.png differ diff --git a/textures/base/pack/refresh.png b/textures/base/pack/refresh.png new file mode 100644 index 000000000..7193677b4 Binary files /dev/null and b/textures/base/pack/refresh.png differ diff --git a/textures/base/pack/server_flags_creative.png b/textures/base/pack/server_flags_creative.png new file mode 100644 index 000000000..fa37a19ca Binary files /dev/null and b/textures/base/pack/server_flags_creative.png differ diff --git a/textures/base/pack/server_flags_damage.png b/textures/base/pack/server_flags_damage.png new file mode 100644 index 000000000..3f0bf0daf Binary files /dev/null and b/textures/base/pack/server_flags_damage.png differ diff --git a/textures/base/pack/server_flags_favorite.png b/textures/base/pack/server_flags_favorite.png new file mode 100644 index 000000000..6a3fc5efe Binary files /dev/null and b/textures/base/pack/server_flags_favorite.png differ diff --git a/textures/base/pack/server_flags_pvp.png b/textures/base/pack/server_flags_pvp.png new file mode 100644 index 000000000..977dfdc0c Binary files /dev/null and b/textures/base/pack/server_flags_pvp.png differ diff --git a/textures/base/pack/server_ping_1.png b/textures/base/pack/server_ping_1.png new file mode 100644 index 000000000..ba5bba1e3 Binary files /dev/null and b/textures/base/pack/server_ping_1.png differ diff --git a/textures/base/pack/server_ping_2.png b/textures/base/pack/server_ping_2.png new file mode 100644 index 000000000..8dca0be0d Binary files /dev/null and b/textures/base/pack/server_ping_2.png differ diff --git a/textures/base/pack/server_ping_3.png b/textures/base/pack/server_ping_3.png new file mode 100644 index 000000000..c2cab017e Binary files /dev/null and b/textures/base/pack/server_ping_3.png differ diff --git a/textures/base/pack/server_ping_4.png b/textures/base/pack/server_ping_4.png new file mode 100644 index 000000000..03b4b5b83 Binary files /dev/null and b/textures/base/pack/server_ping_4.png differ diff --git a/textures/base/pack/smoke_puff.png b/textures/base/pack/smoke_puff.png new file mode 100644 index 000000000..488b50fe9 Binary files /dev/null and b/textures/base/pack/smoke_puff.png differ diff --git a/textures/base/pack/start_icon.png b/textures/base/pack/start_icon.png new file mode 100644 index 000000000..3830fb3ae Binary files /dev/null and b/textures/base/pack/start_icon.png differ diff --git a/textures/base/pack/sunrisebg.png b/textures/base/pack/sunrisebg.png new file mode 100644 index 000000000..335231788 Binary files /dev/null and b/textures/base/pack/sunrisebg.png differ diff --git a/textures/base/pack/unknown_item.png b/textures/base/pack/unknown_item.png new file mode 100644 index 000000000..c8cf616a7 Binary files /dev/null and b/textures/base/pack/unknown_item.png differ diff --git a/textures/base/pack/unknown_node.png b/textures/base/pack/unknown_node.png new file mode 100644 index 000000000..cb59ff467 Binary files /dev/null and b/textures/base/pack/unknown_node.png differ diff --git a/textures/base/pack/unknown_object.png b/textures/base/pack/unknown_object.png new file mode 100644 index 000000000..c0166c31f Binary files /dev/null and b/textures/base/pack/unknown_object.png differ diff --git a/textures/base/pack/wieldhand.png b/textures/base/pack/wieldhand.png new file mode 100644 index 000000000..ff2283afa Binary files /dev/null and b/textures/base/pack/wieldhand.png differ diff --git a/textures/base/pack/zoom.png b/textures/base/pack/zoom.png new file mode 100644 index 000000000..b27c8c8ba Binary files /dev/null and b/textures/base/pack/zoom.png differ diff --git a/textures/texture_packs_here.txt b/textures/texture_packs_here.txt new file mode 100644 index 000000000..52766ac52 --- /dev/null +++ b/textures/texture_packs_here.txt @@ -0,0 +1 @@ +Put your texture pack folders in this folder. Textures in the "server" pack will be used by the server. diff --git a/util/buildbot/buildwin32.sh b/util/buildbot/buildwin32.sh new file mode 100644 index 000000000..7996d3df3 --- /dev/null +++ b/util/buildbot/buildwin32.sh @@ -0,0 +1,172 @@ +#!/bin/bash +set -e + +CORE_GIT=https://github.com/EliasFleckenstein03/dragonfireclient +CORE_BRANCH=master +CORE_NAME=dragonfireclient +GAME_GIT=https://git.minetest.land/Wuzzy/MineClone2 +GAME_BRANCH=master +GAME_NAME=mineclone2 + +dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi +builddir=$1 +mkdir -p $builddir +builddir="$( cd "$builddir" && pwd )" +packagedir=$builddir/packages +libdir=$builddir/libs + +# Test which win32 compiler is present +which i586-mingw32msvc-windres &>/dev/null && toolchain_file=$dir/toolchain_i586-mingw32msvc.cmake +which i686-w64-mingw32-windres &>/dev/null && toolchain_file=$dir/toolchain_i646-w64-mingw32.cmake + +if [ -z "$toolchain_file" ]; then + echo "Unable to determine which mingw32 compiler to use" + exit 1 +fi +echo "Using $toolchain_file" + +irrlicht_version=1.8.4 +ogg_version=1.3.2 +vorbis_version=1.3.5 +curl_version=7.65.3 +gettext_version=0.20.1 +freetype_version=2.10.1 +sqlite3_version=3.27.2 +luajit_version=2.1.0-beta3 +leveldb_version=1.22 +zlib_version=1.2.11 + +mkdir -p $packagedir +mkdir -p $libdir + +cd $builddir + +# Get stuff +[ -e $packagedir/irrlicht-$irrlicht_version.zip ] || wget http://minetest.kitsunemimi.pw/irrlicht-$irrlicht_version-win32.zip \ + -c -O $packagedir/irrlicht-$irrlicht_version.zip +[ -e $packagedir/zlib-$zlib_version.zip ] || wget http://minetest.kitsunemimi.pw/zlib-$zlib_version-win32.zip \ + -c -O $packagedir/zlib-$zlib_version.zip +[ -e $packagedir/libogg-$ogg_version.zip ] || wget http://minetest.kitsunemimi.pw/libogg-$ogg_version-win32.zip \ + -c -O $packagedir/libogg-$ogg_version.zip +[ -e $packagedir/libvorbis-$vorbis_version.zip ] || wget http://minetest.kitsunemimi.pw/libvorbis-$vorbis_version-win32.zip \ + -c -O $packagedir/libvorbis-$vorbis_version.zip +[ -e $packagedir/curl-$curl_version.zip ] || wget http://minetest.kitsunemimi.pw/curl-$curl_version-win32.zip \ + -c -O $packagedir/curl-$curl_version.zip +[ -e $packagedir/gettext-$gettext_version.zip ] || wget http://minetest.kitsunemimi.pw/gettext-$gettext_version-win32.zip \ + -c -O $packagedir/gettext-$gettext_version.zip +[ -e $packagedir/freetype2-$freetype_version.zip ] || wget http://minetest.kitsunemimi.pw/freetype2-$freetype_version-win32.zip \ + -c -O $packagedir/freetype2-$freetype_version.zip +[ -e $packagedir/sqlite3-$sqlite3_version.zip ] || wget http://minetest.kitsunemimi.pw/sqlite3-$sqlite3_version-win32.zip \ + -c -O $packagedir/sqlite3-$sqlite3_version.zip +[ -e $packagedir/luajit-$luajit_version.zip ] || wget http://minetest.kitsunemimi.pw/luajit-$luajit_version-win32.zip \ + -c -O $packagedir/luajit-$luajit_version.zip +[ -e $packagedir/libleveldb-$leveldb_version.zip ] || wget http://minetest.kitsunemimi.pw/libleveldb-$leveldb_version-win32.zip \ + -c -O $packagedir/libleveldb-$leveldb_version.zip +[ -e $packagedir/openal_stripped.zip ] || wget http://minetest.kitsunemimi.pw/openal_stripped.zip \ + -c -O $packagedir/openal_stripped.zip + +# Extract stuff +cd $libdir +[ -d irrlicht ] || unzip -o $packagedir/irrlicht-$irrlicht_version.zip -d irrlicht +[ -d zlib ] || unzip -o $packagedir/zlib-$zlib_version.zip -d zlib +[ -d libogg ] || unzip -o $packagedir/libogg-$ogg_version.zip -d libogg +[ -d libvorbis ] || unzip -o $packagedir/libvorbis-$vorbis_version.zip -d libvorbis +[ -d libcurl ] || unzip -o $packagedir/curl-$curl_version.zip -d libcurl +[ -d gettext ] || unzip -o $packagedir/gettext-$gettext_version.zip -d gettext +[ -d freetype ] || unzip -o $packagedir/freetype2-$freetype_version.zip -d freetype +[ -d sqlite3 ] || unzip -o $packagedir/sqlite3-$sqlite3_version.zip -d sqlite3 +[ -d openal_stripped ] || unzip -o $packagedir/openal_stripped.zip +[ -d luajit ] || unzip -o $packagedir/luajit-$luajit_version.zip -d luajit +[ -d leveldb ] || unzip -o $packagedir/libleveldb-$leveldb_version.zip -d leveldb + +# Get minetest +cd $builddir +if [ ! "x$EXISTING_MINETEST_DIR" = "x" ]; then + cd /$EXISTING_MINETEST_DIR # must be absolute path +else + [ -d $CORE_NAME ] && (cd $CORE_NAME && git pull) || (git clone -b $CORE_BRANCH $CORE_GIT) + cd $CORE_NAME +fi +git_hash=$(git rev-parse --short HEAD) + +# Get minetest_game +if [ "x$NO_MINETEST_GAME" = "x" ]; then + cd games + [ -d $GAME_NAME ] && (cd $GAME_NAME && git pull) || (git clone -b $GAME_BRANCH $GAME_GIT) + cd .. +fi + +# Build the thing +[ -d _build ] && rm -Rf _build/ +mkdir _build +cd _build +cmake .. \ + -DCMAKE_INSTALL_PREFIX=/tmp \ + -DVERSION_EXTRA=$git_hash \ + -DBUILD_CLIENT=1 -DBUILD_SERVER=0 \ + -DCMAKE_TOOLCHAIN_FILE=$toolchain_file \ + \ + -DENABLE_SOUND=1 \ + -DENABLE_CURL=1 \ + -DENABLE_GETTEXT=1 \ + -DENABLE_FREETYPE=1 \ + -DENABLE_LEVELDB=1 \ + \ + -DIRRLICHT_INCLUDE_DIR=$libdir/irrlicht/include \ + -DIRRLICHT_LIBRARY=$libdir/irrlicht/lib/Win32-gcc/libIrrlicht.dll.a \ + -DIRRLICHT_DLL=$libdir/irrlicht/bin/Win32-gcc/Irrlicht.dll \ + \ + -DZLIB_INCLUDE_DIR=$libdir/zlib/include \ + -DZLIB_LIBRARIES=$libdir/zlib/lib/libz.dll.a \ + -DZLIB_DLL=$libdir/zlib/bin/zlib1.dll \ + \ + -DLUA_INCLUDE_DIR=$libdir/luajit/include \ + -DLUA_LIBRARY=$libdir/luajit/libluajit.a \ + \ + -DOGG_INCLUDE_DIR=$libdir/libogg/include \ + -DOGG_LIBRARY=$libdir/libogg/lib/libogg.dll.a \ + -DOGG_DLL=$libdir/libogg/bin/libogg-0.dll \ + \ + -DVORBIS_INCLUDE_DIR=$libdir/libvorbis/include \ + -DVORBIS_LIBRARY=$libdir/libvorbis/lib/libvorbis.dll.a \ + -DVORBIS_DLL=$libdir/libvorbis/bin/libvorbis-0.dll \ + -DVORBISFILE_LIBRARY=$libdir/libvorbis/lib/libvorbisfile.dll.a \ + -DVORBISFILE_DLL=$libdir/libvorbis/bin/libvorbisfile-3.dll \ + \ + -DOPENAL_INCLUDE_DIR=$libdir/openal_stripped/include/AL \ + -DOPENAL_LIBRARY=$libdir/openal_stripped/lib/libOpenAL32.dll.a \ + -DOPENAL_DLL=$libdir/openal_stripped/bin/OpenAL32.dll \ + \ + -DCURL_DLL=$libdir/libcurl/bin/libcurl-4.dll \ + -DCURL_INCLUDE_DIR=$libdir/libcurl/include \ + -DCURL_LIBRARY=$libdir/libcurl/lib/libcurl.dll.a \ + \ + -DGETTEXT_MSGFMT=`which msgfmt` \ + -DGETTEXT_DLL=$libdir/gettext/bin/libintl-8.dll \ + -DGETTEXT_ICONV_DLL=$libdir/gettext/bin/libiconv-2.dll \ + -DGETTEXT_INCLUDE_DIR=$libdir/gettext/include \ + -DGETTEXT_LIBRARY=$libdir/gettext/lib/libintl.dll.a \ + \ + -DFREETYPE_INCLUDE_DIR_freetype2=$libdir/freetype/include/freetype2 \ + -DFREETYPE_INCLUDE_DIR_ft2build=$libdir/freetype/include/freetype2 \ + -DFREETYPE_LIBRARY=$libdir/freetype/lib/libfreetype.dll.a \ + -DFREETYPE_DLL=$libdir/freetype/bin/libfreetype-6.dll \ + \ + -DSQLITE3_INCLUDE_DIR=$libdir/sqlite3/include \ + -DSQLITE3_LIBRARY=$libdir/sqlite3/lib/libsqlite3.dll.a \ + -DSQLITE3_DLL=$libdir/sqlite3/bin/libsqlite3-0.dll \ + \ + -DLEVELDB_INCLUDE_DIR=$libdir/leveldb/include \ + -DLEVELDB_LIBRARY=$libdir/leveldb/lib/libleveldb.dll.a \ + -DLEVELDB_DLL=$libdir/leveldb/bin/libleveldb.dll + +make -j$(nproc) + +[ "x$NO_PACKAGE" = "x" ] && make package + +exit 0 +# EOF diff --git a/util/buildbot/buildwin64.sh b/util/buildbot/buildwin64.sh new file mode 100644 index 000000000..df0d61154 --- /dev/null +++ b/util/buildbot/buildwin64.sh @@ -0,0 +1,164 @@ +#!/bin/bash +set -e + +CORE_GIT=https://github.com/EliasFleckenstein03/dragonfireclient +CORE_BRANCH=master +CORE_NAME=dragonfireclient +GAME_GIT=https://git.minetest.land/Wuzzy/MineClone2 +GAME_BRANCH=master +GAME_NAME=mineclone2 + +dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi +builddir=$1 +mkdir -p $builddir +builddir="$( cd "$builddir" && pwd )" +packagedir=$builddir/packages +libdir=$builddir/libs + +toolchain_file=$dir/toolchain_x86_64-w64-mingw32.cmake +irrlicht_version=1.8.4 +ogg_version=1.3.2 +vorbis_version=1.3.5 +curl_version=7.65.3 +gettext_version=0.20.1 +freetype_version=2.10.1 +sqlite3_version=3.27.2 +luajit_version=2.1.0-beta3 +leveldb_version=1.22 +zlib_version=1.2.11 + +mkdir -p $packagedir +mkdir -p $libdir + +cd $builddir + +# Get stuff +[ -e $packagedir/irrlicht-$irrlicht_version.zip ] || wget http://minetest.kitsunemimi.pw/irrlicht-$irrlicht_version-win64.zip \ + -c -O $packagedir/irrlicht-$irrlicht_version.zip +[ -e $packagedir/zlib-$zlib_version.zip ] || wget http://minetest.kitsunemimi.pw/zlib-$zlib_version-win64.zip \ + -c -O $packagedir/zlib-$zlib_version.zip +[ -e $packagedir/libogg-$ogg_version.zip ] || wget http://minetest.kitsunemimi.pw/libogg-$ogg_version-win64.zip \ + -c -O $packagedir/libogg-$ogg_version.zip +[ -e $packagedir/libvorbis-$vorbis_version.zip ] || wget http://minetest.kitsunemimi.pw/libvorbis-$vorbis_version-win64.zip \ + -c -O $packagedir/libvorbis-$vorbis_version.zip +[ -e $packagedir/curl-$curl_version.zip ] || wget http://minetest.kitsunemimi.pw/curl-$curl_version-win64.zip \ + -c -O $packagedir/curl-$curl_version.zip +[ -e $packagedir/gettext-$gettext_version.zip ] || wget http://minetest.kitsunemimi.pw/gettext-$gettext_version-win64.zip \ + -c -O $packagedir/gettext-$gettext_version.zip +[ -e $packagedir/freetype2-$freetype_version.zip ] || wget http://minetest.kitsunemimi.pw/freetype2-$freetype_version-win64.zip \ + -c -O $packagedir/freetype2-$freetype_version.zip +[ -e $packagedir/sqlite3-$sqlite3_version.zip ] || wget http://minetest.kitsunemimi.pw/sqlite3-$sqlite3_version-win64.zip \ + -c -O $packagedir/sqlite3-$sqlite3_version.zip +[ -e $packagedir/luajit-$luajit_version.zip ] || wget http://minetest.kitsunemimi.pw/luajit-$luajit_version-win64.zip \ + -c -O $packagedir/luajit-$luajit_version.zip +[ -e $packagedir/libleveldb-$leveldb_version.zip ] || wget http://minetest.kitsunemimi.pw/libleveldb-$leveldb_version-win64.zip \ + -c -O $packagedir/libleveldb-$leveldb_version.zip +[ -e $packagedir/openal_stripped.zip ] || wget http://minetest.kitsunemimi.pw/openal_stripped64.zip \ + -c -O $packagedir/openal_stripped.zip + + +# Extract stuff +cd $libdir +[ -d irrlicht ] || unzip -o $packagedir/irrlicht-$irrlicht_version.zip -d irrlicht +[ -d zlib ] || unzip -o $packagedir/zlib-$zlib_version.zip -d zlib +[ -d libogg ] || unzip -o $packagedir/libogg-$ogg_version.zip -d libogg +[ -d libvorbis ] || unzip -o $packagedir/libvorbis-$vorbis_version.zip -d libvorbis +[ -d libcurl ] || unzip -o $packagedir/curl-$curl_version.zip -d libcurl +[ -d gettext ] || unzip -o $packagedir/gettext-$gettext_version.zip -d gettext +[ -d freetype ] || unzip -o $packagedir/freetype2-$freetype_version.zip -d freetype +[ -d sqlite3 ] || unzip -o $packagedir/sqlite3-$sqlite3_version.zip -d sqlite3 +[ -d openal_stripped ] || unzip -o $packagedir/openal_stripped.zip +[ -d luajit ] || unzip -o $packagedir/luajit-$luajit_version.zip -d luajit +[ -d leveldb ] || unzip -o $packagedir/libleveldb-$leveldb_version.zip -d leveldb + +# Get minetest +cd $builddir +if [ ! "x$EXISTING_MINETEST_DIR" = "x" ]; then + cd /$EXISTING_MINETEST_DIR # must be absolute path +else + [ -d $CORE_NAME ] && (cd $CORE_NAME && git pull) || (git clone -b $CORE_BRANCH $CORE_GIT) + cd $CORE_NAME +fi +git_hash=$(git rev-parse --short HEAD) + +# Get minetest_game +if [ "x$NO_MINETEST_GAME" = "x" ]; then + cd games + [ -d $GAME_NAME ] && (cd $GAME_NAME && git pull) || (git clone -b $GAME_BRANCH $GAME_GIT) + cd .. +fi + +# Build the thing +[ -d _build ] && rm -Rf _build/ +mkdir _build +cd _build +cmake .. \ + -DCMAKE_TOOLCHAIN_FILE=$toolchain_file \ + -DCMAKE_INSTALL_PREFIX=/tmp \ + -DVERSION_EXTRA=$git_hash \ + -DBUILD_CLIENT=1 -DBUILD_SERVER=0 \ + \ + -DENABLE_SOUND=1 \ + -DENABLE_CURL=1 \ + -DENABLE_GETTEXT=1 \ + -DENABLE_FREETYPE=1 \ + -DENABLE_LEVELDB=1 \ + \ + -DIRRLICHT_INCLUDE_DIR=$libdir/irrlicht/include \ + -DIRRLICHT_LIBRARY=$libdir/irrlicht/lib/Win64-gcc/libIrrlicht.dll.a \ + -DIRRLICHT_DLL=$libdir/irrlicht/bin/Win64-gcc/Irrlicht.dll \ + \ + -DZLIB_INCLUDE_DIR=$libdir/zlib/include \ + -DZLIB_LIBRARIES=$libdir/zlib/lib/libz.dll.a \ + -DZLIB_DLL=$libdir/zlib/bin/zlib1.dll \ + \ + -DLUA_INCLUDE_DIR=$libdir/luajit/include \ + -DLUA_LIBRARY=$libdir/luajit/libluajit.a \ + \ + -DOGG_INCLUDE_DIR=$libdir/libogg/include \ + -DOGG_LIBRARY=$libdir/libogg/lib/libogg.dll.a \ + -DOGG_DLL=$libdir/libogg/bin/libogg-0.dll \ + \ + -DVORBIS_INCLUDE_DIR=$libdir/libvorbis/include \ + -DVORBIS_LIBRARY=$libdir/libvorbis/lib/libvorbis.dll.a \ + -DVORBIS_DLL=$libdir/libvorbis/bin/libvorbis-0.dll \ + -DVORBISFILE_LIBRARY=$libdir/libvorbis/lib/libvorbisfile.dll.a \ + -DVORBISFILE_DLL=$libdir/libvorbis/bin/libvorbisfile-3.dll \ + \ + -DOPENAL_INCLUDE_DIR=$libdir/openal_stripped/include/AL \ + -DOPENAL_LIBRARY=$libdir/openal_stripped/lib/libOpenAL32.dll.a \ + -DOPENAL_DLL=$libdir/openal_stripped/bin/OpenAL32.dll \ + \ + -DCURL_DLL=$libdir/libcurl/bin/libcurl-4.dll \ + -DCURL_INCLUDE_DIR=$libdir/libcurl/include \ + -DCURL_LIBRARY=$libdir/libcurl/lib/libcurl.dll.a \ + \ + -DGETTEXT_MSGFMT=`which msgfmt` \ + -DGETTEXT_DLL=$libdir/gettext/bin/libintl-8.dll \ + -DGETTEXT_ICONV_DLL=$libdir/gettext/bin/libiconv-2.dll \ + -DGETTEXT_INCLUDE_DIR=$libdir/gettext/include \ + -DGETTEXT_LIBRARY=$libdir/gettext/lib/libintl.dll.a \ + \ + -DFREETYPE_INCLUDE_DIR_freetype2=$libdir/freetype/include/freetype2 \ + -DFREETYPE_INCLUDE_DIR_ft2build=$libdir/freetype/include/freetype2 \ + -DFREETYPE_LIBRARY=$libdir/freetype/lib/libfreetype.dll.a \ + -DFREETYPE_DLL=$libdir/freetype/bin/libfreetype-6.dll \ + \ + -DSQLITE3_INCLUDE_DIR=$libdir/sqlite3/include \ + -DSQLITE3_LIBRARY=$libdir/sqlite3/lib/libsqlite3.dll.a \ + -DSQLITE3_DLL=$libdir/sqlite3/bin/libsqlite3-0.dll \ + \ + -DLEVELDB_INCLUDE_DIR=$libdir/leveldb/include \ + -DLEVELDB_LIBRARY=$libdir/leveldb/lib/libleveldb.dll.a \ + -DLEVELDB_DLL=$libdir/leveldb/bin/libleveldb.dll + +make -j$(nproc) + +[ "x$NO_PACKAGE" = "x" ] && make package + +exit 0 +# EOF diff --git a/util/buildbot/toolchain_i586-mingw32msvc.cmake b/util/buildbot/toolchain_i586-mingw32msvc.cmake new file mode 100644 index 000000000..96a434832 --- /dev/null +++ b/util/buildbot/toolchain_i586-mingw32msvc.cmake @@ -0,0 +1,17 @@ +# name of the target operating system +SET(CMAKE_SYSTEM_NAME Windows) + +# which compilers to use for C and C++ +SET(CMAKE_C_COMPILER i586-mingw32msvc-gcc) +SET(CMAKE_CXX_COMPILER i586-mingw32msvc-g++) +SET(CMAKE_RC_COMPILER i586-mingw32msvc-windres) + +# here is the target environment located +SET(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/util/buildbot/toolchain_i646-w64-mingw32.cmake b/util/buildbot/toolchain_i646-w64-mingw32.cmake new file mode 100644 index 000000000..ac03a60bc --- /dev/null +++ b/util/buildbot/toolchain_i646-w64-mingw32.cmake @@ -0,0 +1,17 @@ +# name of the target operating system +SET(CMAKE_SYSTEM_NAME Windows) + +# which compilers to use for C and C++ +SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc) +SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) +SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres) + +# here is the target environment located +SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/util/buildbot/toolchain_x86_64-w64-mingw32.cmake b/util/buildbot/toolchain_x86_64-w64-mingw32.cmake new file mode 100644 index 000000000..be9d3cc90 --- /dev/null +++ b/util/buildbot/toolchain_x86_64-w64-mingw32.cmake @@ -0,0 +1,17 @@ +# name of the target operating system +SET(CMAKE_SYSTEM_NAME Windows) + +# which compilers to use for C and C++ +SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) +SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) +SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + +# here is the target environment located +SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) + +# adjust the default behaviour of the FIND_XXX() commands: +# search headers and libraries in the target environment, search +# programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/util/bump_version.sh b/util/bump_version.sh new file mode 100644 index 000000000..81bbeeb5b --- /dev/null +++ b/util/bump_version.sh @@ -0,0 +1,138 @@ +#!/bin/bash -e + +prompt_for_number() { + local prompt_text=$1 + local default_value=$2 + local tmp="" + while true; do + read -p "$prompt_text [$default_value]: " tmp + if [ "$tmp" = "" ]; then + echo "$default_value"; return + elif echo "$tmp" | grep -q -E '^[0-9]+$'; then + echo "$tmp"; return + fi + done +} + +# On a release the following actions are performed +# * DEVELOPMENT_BUILD is set to false +# * android versionCode is bumped +# * appdata release version and date are updated +# * Commit the changes +# * Tag with current version +perform_release() { + sed -i -re "s/^set\(DEVELOPMENT_BUILD TRUE\)$/set(DEVELOPMENT_BUILD FALSE)/" CMakeLists.txt + + sed -i -re "s/\"versionCode\", [0-9]+/\"versionCode\", $NEW_ANDROID_VERSION_CODE/" build/android/build.gradle + + sed -i '/\] [--filter|-f ]" + echo " [--wrap|-w] [--heightalpha|-a] [--invertx|-x] [--inverty|-y]" + echo " [--conversion|-c ] [--skiptools|-t] [--skipinventory|-i []]" + echo " [--dryrun|-d] [--pattern|-p ]" + echo -e "\nDefaults to a scale of 8, checking all files in the current directory, and not" + echo "skipping apparent tools or inventory images. Filter, if specified, may be one" + echo "of: sobel3, sobel5, prewitt3, prewitt5, 3x3, 5x5, 7x7, or 9x9, or a value 1" + echo "through 8 (1=sobel3, 2=sobel5, etc.). Defaults to 0 (four-sample). The height" + echo "source is taken from the image's alpha channel if heightalpha is specified.\n" + echo "" + echo "If inventory skip is specified, an optional resolution may also be included" + echo "(default is 64). Conversion can be one of: biased, red, green, blue, maxrgb," + echo "minrgb, colorspace, normalize-only, heightmap or a value from 1 to 9" + echo "corresponding respectively to those keywords. Defaults to 0 (simple" + echo "normalize) if not specified. Wrap, if specified, enables wrapping of the" + echo "normalmap around the edges of the texture (defaults to no). Invert X/Y" + echo "reverses the calculated gradients for the X and/or Y dimensions represented" + echo "by the normalmap (both default to non-inverted)." + echo "" + echo "The pattern, can be an escaped pattern string such as \*apple\* or" + echo "default_\*.png or similar (defaults to all PNG and JPG images in the current" + echo "directory that do not contain \"_normal\" or \"_specular\" in their filenames)." + echo "" + echo "If set for dry-run, the actions this script will take will be printed, but no" + echo "images will be generated. Passing an invalid value to a switch will generally" + echo "cause that switch to revert to its default value." + echo "" + exit 1 + ;; + esac +done + +echo -e "\nProcessing files based on pattern \"$pattern\" ..." + +normalMap() +{ + out=`echo "$1" | sed 's/.png/_normal.png/' | sed 's/.jpg/_normal.png/'` + + echo "Launched process to generate normalmap: \"$1\" --> \"$out\"" >&2 + + gimp -i -b " + (define + (normalMap-fbx-conversion fileName newFileName filter nscale wrap heightsource conversion invertx inverty) + (let* + ( + (image (car (gimp-file-load RUN-NONINTERACTIVE fileName fileName))) + (drawable (car (gimp-image-get-active-layer image))) + (drawable (car (gimp-image-flatten image))) + ) + (if (> (car (gimp-drawable-type drawable)) 1) + (gimp-convert-rgb image) () + ) + + (plug-in-normalmap + RUN-NONINTERACTIVE + image + drawable + filter + 0.0 + nscale + wrap + heightsource + 0 + conversion + 0 + invertx + inverty + 0 + 0.0 + drawable) + (gimp-file-save RUN-NONINTERACTIVE image drawable newFileName newFileName) + (gimp-image-delete image) + ) + ) + (normalMap-fbx-conversion \"$1\" \"$out\" $2 $3 $4 $5 $6 $7 $8)" -b '(gimp-quit 0)' +} + +export -f normalMap + +for file in `ls $pattern |grep -v "_normal.png"|grep -v "_specular"` ; do + + invtest=`file "$file" |grep "$invresolution x $invresolution"` + if $skipinventory && [ -n "$invtest" ] ; then + echo "Skipped presumed "$invresolution"px inventory image: $file" >&2 + continue + fi + + tooltest=`echo "$file" \ + | grep -v "_tool" \ + | grep -v "_shovel" \ + | grep -v "_pick" \ + | grep -v "_axe" \ + | grep -v "_sword" \ + | grep -v "_hoe" \ + | grep -v "bucket_"` + + if $skiptools && [ -z "$tooltest" ] ; then + echo "Skipped presumed tool image: $file" >&2 + continue + fi + + if $dryrun ; then + echo "Would have generated a normalmap for $file" >&2 + continue + else + echo \"$file\" $filter $scale $wrap $heightsource $conversion $invertx $inverty + fi +done | xargs -P $numprocs -n 8 -I{} bash -c normalMap\ \{\}\ \{\}\ \{\}\ \{\}\ \{\}\ \{\}\ \{\}\ \{\} + diff --git a/util/reorder_translation_commits.py b/util/reorder_translation_commits.py new file mode 100644 index 000000000..767f30475 --- /dev/null +++ b/util/reorder_translation_commits.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +import sys +import subprocess + +ret = subprocess.run(["git", "config", "rebase.instructionFormat"], capture_output=True) +if ret.returncode != 0 or ret.stdout.decode('ascii').strip() != "(%an <%ae>) %s": + print("Git is using the wrong rebase instruction format, reconfigure it.") + exit(1) + +try: + f = open(".git/rebase-merge/git-rebase-todo", "r") +except: + print("Initiate the rebase first!") + exit(1) +lines = list(s.strip("\r\n") for s in f.readlines()) +f.close() + +for i in range(len(lines)): + line = lines[i] + if line.startswith("#") or " Translated using Weblate " not in line: continue + pos = line.rfind("(") + lang = line[pos:] + author = line[line.find("("):line.rfind(")", 0, pos)+1] + # try to grab the next commit by the same author for the same language + for j in range(i+1, len(lines)): + if lines[j].startswith("#") or not lines[j].endswith(lang): continue + if author in lines[j]: + lines.insert(i+1, "f " + lines.pop(j)[5:]) + break + +with open(".git/rebase-merge/git-rebase-todo", "w") as f: + f.write("\n".join(lines) + "\n") +print("You can now continue with the rebase.") diff --git a/util/test_multiplayer.sh b/util/test_multiplayer.sh new file mode 100644 index 000000000..c393bf894 --- /dev/null +++ b/util/test_multiplayer.sh @@ -0,0 +1,43 @@ +#!/bin/bash +dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +gameid=devtest +minetest=$dir/../bin/minetest +testspath=$dir/../tests +worldpath=$testspath/testworld_$gameid +configpath=$testspath/configs +logpath=$testspath/log +conf_server=$configpath/minetest.conf.multi.server +conf_client1=$configpath/minetest.conf.multi.client1 +conf_client2=$configpath/minetest.conf.multi.client2 +log_server=$logpath/server.log +log_client1=$logpath/client1.log +log_client2=$logpath/client2.log + +mkdir -p $worldpath +mkdir -p $configpath +mkdir -p $logpath + +echo -ne 'client1::shout,interact,settime,teleport,give +client2::shout,interact,settime,teleport,give +' > $worldpath/auth.txt + +echo -ne '' > $conf_server + +echo -ne '# client 1 config +screenW=500 +screenH=380 +name=client1 +viewing_range_nodes_min=10 +' > $conf_client1 + +echo -ne '# client 2 config +screenW=500 +screenH=380 +name=client2 +viewing_range_nodes_min=10 +' > $conf_client2 + +echo $(sleep 1; $minetest --disable-unittests --logfile $log_client1 --config $conf_client1 --go --address localhost) & +echo $(sleep 2; $minetest --disable-unittests --logfile $log_client2 --config $conf_client2 --go --address localhost) & +$minetest --disable-unittests --server --logfile $log_server --config $conf_server --world $worldpath --gameid $gameid + diff --git a/util/updatepo.sh b/util/updatepo.sh new file mode 100644 index 000000000..f9bcf771a --- /dev/null +++ b/util/updatepo.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +# Update/create minetest po files + +# an auxiliary function to abort processing with an optional error +# message +abort() { + test -n "$1" && echo >&2 "$1" + exit 1 +} + +# The po/ directory is assumed to be parallel to the directory where +# this script is. Relative paths are fine for us so we can just +# use the following trick (works both for manual invocations and for +# script found from PATH) +scriptisin="$(dirname "$(which "$0")")" + +# The script is executed from the parent of po/, which is also the +# parent of the script directory and of the src/ directory. +# We go through $scriptisin so that it can be executed from whatever +# directory and still work correctly +cd "$scriptisin/.." + +test -e po || abort "po/ directory not found" +test -d po || abort "po/ is not a directory!" + +# Get a list of the languages we have to update/create + +cd po || abort "couldn't change directory to po!" + +# This assumes that we won't have dirnames with space, which is +# the case for language codes, which are the only subdirs we expect to +# find in po/ anyway. If you put anything else there, you need to suffer +# the consequences of your actions, so we don't do sanity checks +langs="" + +for lang in * ; do + if test ! -d $lang; then + continue + fi + langs="$langs $lang" +done + +# go back +cd .. + +# First thing first, update the .pot template. We place it in the po/ +# directory at the top level. You a recent enough xgettext that supports +# --package-name +potfile=po/minetest.pot +xgettext --package-name=minetest \ + --add-comments='~' \ + --sort-by-file \ + --add-location=file \ + --keyword=N_ \ + --keyword=wgettext \ + --keyword=fgettext \ + --keyword=fgettext_ne \ + --keyword=strgettext \ + --keyword=wstrgettext \ + --keyword=showTranslatedStatusText \ + --output $potfile \ + --from-code=utf-8 \ + `find src/ -name '*.cpp' -o -name '*.h'` \ + `find builtin/ -name '*.lua'` + +# Now iterate on all languages and create the po file if missing, or update it +# if it exists already +for lang in $langs ; do # note the missing quotes around $langs + pofile=po/$lang/minetest.po + if test -e $pofile; then + echo "[$lang]: updating strings" + msgmerge --update --sort-by-file $pofile $potfile + else + # This will ask for the translator identity + echo "[$lang]: NEW strings" + msginit --locale=$lang --output-file=$pofile --input=$potfile + fi +done diff --git a/util/wireshark/minetest.lua b/util/wireshark/minetest.lua new file mode 100644 index 000000000..9a930da8d --- /dev/null +++ b/util/wireshark/minetest.lua @@ -0,0 +1,1444 @@ +-- minetest.lua +-- Packet dissector for the UDP-based Minetest protocol +-- Copy this to $HOME/.wireshark/plugins/ + + +-- +-- Minetest +-- Copyright (C) 2011 celeron55, Perttu Ahola +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along +-- with this program; if not, write to the Free Software Foundation, Inc., +-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +-- + + +-- Wireshark documentation: +-- https://web.archive.org/web/20170711121726/https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Proto.html +-- https://web.archive.org/web/20170711121844/https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Tree.html +-- https://web.archive.org/web/20170711121917/https://www.wireshark.org/docs/wsdg_html_chunked/lua_module_Tvb.html + + +-- Table of Contents: +-- Part 1: Utility functions +-- Part 2: Client command dissectors (TOSERVER_*) +-- Part 3: Server command dissectors (TOCLIENT_*) +-- Part 4: Wrapper protocol subdissectors +-- Part 5: Wrapper protocol main dissector +-- Part 6: Utility functions part 2 + + +----------------------- +-- Part 1 -- +-- Utility functions -- +----------------------- + +-- Creates two ProtoFields to hold a length and variable-length text content +-- lentype must be either "uint16" or "uint32" +function minetest_field_helper(lentype, name, abbr) + local f_textlen = ProtoField[lentype](name .. "len", abbr .. " (length)", base.DEC) + local f_text = ProtoField.string(name, abbr) + return f_textlen, f_text +end + + + + +-------------------------------------------- +-- Part 2 -- +-- Client command dissectors (TOSERVER_*) -- +-------------------------------------------- + +minetest_client_commands = {} +minetest_client_obsolete = {} + +-- TOSERVER_INIT + +do + local abbr = "minetest.client.init_" + + local f_ser_fmt = ProtoField.uint8(abbr.."ser_version", + "Maximum serialization format version", base.DEC) + local f_comp_modes = ProtoField.uint16(abbr.."compression", + "Supported compression modes", base.DEC, { [0] = "No compression" }) + local f_proto_min = ProtoField.uint16(abbr.."proto_min", "Minimum protocol version", base.DEC) + local f_proto_max = ProtoField.uint16(abbr.."_proto_max", "Maximum protocol version", base.DEC) + local f_player_namelen, f_player_name = + minetest_field_helper("uint16", abbr.."player_name", "Player Name") + + minetest_client_commands[0x02] = { + "INIT", -- Command name + 11, -- Minimum message length including code + { f_ser_fmt, -- List of fields [optional] + f_comp_modes, + f_proto_min, + f_proto_max, + f_player_namelen, + f_player_name }, + function(buffer, pinfo, tree, t) -- Dissector function [optional] + t:add(f_ser_fmt, buffer(2,1)) + t:add(f_comp_modes, buffer(3,2)) + t:add(f_proto_min, buffer(5,2)) + t:add(f_proto_max, buffer(7,2)) + minetest_decode_helper_ascii(buffer, t, "uint16", 9, f_player_namelen, f_player_name) + end + } +end + +-- TOSERVER_INIT_LEGACY (obsolete) + +minetest_client_commands[0x10] = { "INIT_LEGACY", 53 } +minetest_client_obsolete[0x10] = true + +-- TOSERVER_INIT2 + +do + local f_langlen, f_lang = + minetest_field_helper("uint16", "minetest.client.init2_language", "Language Code") + + minetest_client_commands[0x11] = { + "INIT2", + 2, + { f_langlen, + f_lang }, + function(buffer, pinfo, tree, t) + minetest_decode_helper_ascii(buffer, t, "uint16", 2, f_langlen, f_lang) + end + } +end + +-- TOSERVER_MODCHANNEL_JOIN + +minetest_client_commands[0x17] = { "MODCHANNEL_JOIN", 2 } + +-- TOSERVER_MODCHANNEL_LEAVE + +minetest_client_commands[0x18] = { "MODCHANNEL_LEAVE", 2 } + +-- TOSERVER_MODCHANNEL_MSG + +minetest_client_commands[0x19] = { "MODCHANNEL_MSG", 2 } + +-- TOSERVER_GETBLOCK (obsolete) + +minetest_client_commands[0x20] = { "GETBLOCK", 2 } +minetest_client_obsolete[0x20] = true + +-- TOSERVER_ADDNODE (obsolete) + +minetest_client_commands[0x21] = { "ADDNODE", 2 } +minetest_client_obsolete[0x21] = true + +-- TOSERVER_REMOVENODE (obsolete) + +minetest_client_commands[0x22] = { "REMOVENODE", 2 } +minetest_client_obsolete[0x22] = true + +-- TOSERVER_PLAYERPOS + +do + local abbr = "minetest.client.playerpos_" + + local f_x = ProtoField.int32(abbr.."x", "Position X", base.DEC) + local f_y = ProtoField.int32(abbr.."y", "Position Y", base.DEC) + local f_z = ProtoField.int32(abbr.."z", "Position Z", base.DEC) + local f_speed_x = ProtoField.int32(abbr.."speed_x", "Speed X", base.DEC) + local f_speed_y = ProtoField.int32(abbr.."speed_y", "Speed Y", base.DEC) + local f_speed_z = ProtoField.int32(abbr.."speed_z", "Speed Z", base.DEC) + local f_pitch = ProtoField.int32(abbr.."pitch", "Pitch", base.DEC) + local f_yaw = ProtoField.int32(abbr.."yaw", "Yaw", base.DEC) + local f_key_pressed = ProtoField.bytes(abbr.."key_pressed", "Pressed keys") + local f_fov = ProtoField.uint8(abbr.."fov", "FOV", base.DEC) + local f_wanted_range = ProtoField.uint8(abbr.."wanted_range", "Requested view range", base.DEC) + + minetest_client_commands[0x23] = { + "PLAYERPOS", 34, + { f_x, f_y, f_z, f_speed_x, f_speed_y, f_speed_z, f_pitch, f_yaw, + f_key_pressed, f_fov, f_wanted_range }, + function(buffer, pinfo, tree, t) + t:add(f_x, buffer(2,4)) + t:add(f_y, buffer(6,4)) + t:add(f_z, buffer(10,4)) + t:add(f_speed_x, buffer(14,4)) + t:add(f_speed_y, buffer(18,4)) + t:add(f_speed_z, buffer(22,4)) + t:add(f_pitch, buffer(26,4)) + t:add(f_yaw, buffer(30,4)) + t:add(f_key_pressed, buffer(34,4)) + t:add(f_fov, buffer(38,1)) + t:add(f_wanted_range, buffer(39,1)) + end + } +end + +-- TOSERVER_GOTBLOCKS + +do + local f_count = ProtoField.uint8("minetest.client.gotblocks_count", "Count", base.DEC) + local f_block = ProtoField.bytes("minetest.client.gotblocks_block", "Block", base.NONE) + local f_x = ProtoField.int16("minetest.client.gotblocks_x", "Block position X", base.DEC) + local f_y = ProtoField.int16("minetest.client.gotblocks_y", "Block position Y", base.DEC) + local f_z = ProtoField.int16("minetest.client.gotblocks_z", "Block position Z", base.DEC) + + minetest_client_commands[0x24] = { + "GOTBLOCKS", 3, + { f_count, f_block, f_x, f_y, f_z }, + function(buffer, pinfo, tree, t) + t:add(f_count, buffer(2,1)) + local count = buffer(2,1):uint() + if minetest_check_length(buffer, 3 + 6*count, t) then + pinfo.cols.info:append(" * " .. count) + local index + for index = 0, count - 1 do + local pos = 3 + 6*index + local t2 = t:add(f_block, buffer(pos, 6)) + t2:set_text("Block, X: " .. buffer(pos, 2):int() + .. ", Y: " .. buffer(pos + 2, 2):int() + .. ", Z: " .. buffer(pos + 4, 2):int()) + t2:add(f_x, buffer(pos, 2)) + t2:add(f_y, buffer(pos + 2, 2)) + t2:add(f_z, buffer(pos + 4, 2)) + end + end + end + } +end + +-- TOSERVER_DELETEDBLOCKS + +do + local f_count = ProtoField.uint8("minetest.client.deletedblocks_count", "Count", base.DEC) + local f_block = ProtoField.bytes("minetest.client.deletedblocks_block", "Block", base.NONE) + local f_x = ProtoField.int16("minetest.client.deletedblocks_x", "Block position X", base.DEC) + local f_y = ProtoField.int16("minetest.client.deletedblocks_y", "Block position Y", base.DEC) + local f_z = ProtoField.int16("minetest.client.deletedblocks_z", "Block position Z", base.DEC) + + minetest_client_commands[0x25] = { + "DELETEDBLOCKS", 3, + { f_count, f_block, f_x, f_y, f_z }, + function(buffer, pinfo, tree, t) + t:add(f_count, buffer(2,1)) + local count = buffer(2,1):uint() + if minetest_check_length(buffer, 3 + 6*count, t) then + pinfo.cols.info:append(" * " .. count) + local index + for index = 0, count - 1 do + local pos = 3 + 6*index + local t2 = t:add(f_block, buffer(pos, 6)) + t2:set_text("Block, X: " .. buffer(pos, 2):int() + .. ", Y: " .. buffer(pos + 2, 2):int() + .. ", Z: " .. buffer(pos + 4, 2):int()) + t2:add(f_x, buffer(pos, 2)) + t2:add(f_y, buffer(pos + 2, 2)) + t2:add(f_z, buffer(pos + 4, 2)) + end + end + end + } +end + +-- TOSERVER_ADDNODE_FROM_INVENTORY (obsolete) + +minetest_client_commands[0x26] = { "ADDNODE_FROM_INVENTORY", 2 } +minetest_client_obsolete[0x26] = true + +-- TOSERVER_CLICK_OBJECT (obsolete) + +minetest_client_commands[0x27] = { "CLICK_OBJECT", 2 } +minetest_client_obsolete[0x27] = true + +-- TOSERVER_GROUND_ACTION (obsolete) + +minetest_client_commands[0x28] = { "GROUND_ACTION", 2 } +minetest_client_obsolete[0x28] = true + +-- TOSERVER_RELEASE (obsolete) + +minetest_client_commands[0x29] = { "RELEASE", 2 } +minetest_client_obsolete[0x29] = true + +-- TOSERVER_SIGNTEXT (obsolete) + +minetest_client_commands[0x30] = { "SIGNTEXT", 2 } +minetest_client_obsolete[0x30] = true + +-- TOSERVER_INVENTORY_ACTION + +do + local f_action = ProtoField.string("minetest.client.inventory_action", "Action") + + minetest_client_commands[0x31] = { + "INVENTORY_ACTION", 2, + { f_action }, + function(buffer, pinfo, tree, t) + t:add(f_action, buffer(2, buffer:len() - 2)) + end + } +end + +-- TOSERVER_CHAT_MESSAGE + +do + local f_length = ProtoField.uint16("minetest.client.chat_message_length", "Length", base.DEC) + local f_message = ProtoField.string("minetest.client.chat_message", "Message") + + minetest_client_commands[0x32] = { + "CHAT_MESSAGE", 4, + { f_length, f_message }, + function(buffer, pinfo, tree, t) + t:add(f_length, buffer(2,2)) + local textlen = buffer(2,2):uint() + if minetest_check_length(buffer, 4 + textlen*2, t) then + t:add(f_message, minetest_convert_utf16(buffer(4, textlen*2), "Converted chat message")) + end + end + } +end + +-- TOSERVER_SIGNNODETEXT (obsolete) + +minetest_client_commands[0x33] = { "SIGNNODETEXT", 2 } +minetest_client_obsolete[0x33] = true + + +-- TOSERVER_CLICK_ACTIVEOBJECT (obsolete) + +minetest_client_commands[0x34] = { "CLICK_ACTIVEOBJECT", 2 } +minetest_client_obsolete[0x34] = true + +-- TOSERVER_DAMAGE + +do + local f_amount = ProtoField.uint8("minetest.client.damage_amount", "Amount", base.DEC) + + minetest_client_commands[0x35] = { + "DAMAGE", 3, + { f_amount }, + function(buffer, pinfo, tree, t) + t:add(f_amount, buffer(2,1)) + end + } +end + +-- TOSERVER_PASSWORD (obsolete) + +minetest_client_commands[0x36] = { "CLICK_ACTIVEOBJECT", 2 } +minetest_client_obsolete[0x36] = true + +-- TOSERVER_PLAYERITEM + +do + local f_item = ProtoField.uint16("minetest.client.playeritem_item", "Wielded item") + + minetest_client_commands[0x37] = { + "PLAYERITEM", 4, + { f_item }, + function(buffer, pinfo, tree, t) + t:add(f_item, buffer(2,2)) + end + } +end + +-- TOSERVER_RESPAWN + +minetest_client_commands[0x38] = { "RESPAWN", 2 } + +-- TOSERVER_INTERACT + +do + local abbr = "minetest.client.interact_" + local vs_action = { + [0] = "Start digging", + [1] = "Stop digging", + [2] = "Digging completed", + [3] = "Place block or item", + [4] = "Use item", + [5] = "Activate held item", + } + local vs_pointed_type = { + [0] = "Nothing", + [1] = "Node", + [2] = "Object", + } + + local f_action = ProtoField.uint8(abbr.."action", "Action", base.DEC, vs_action) + local f_item = ProtoField.uint16(abbr.."item", "Item Index", base.DEC) + local f_plen = ProtoField.uint32(abbr.."plen", "Length of pointed thing", base.DEC) + local f_pointed_version = ProtoField.uint8(abbr.."pointed_version", + "Pointed Thing Version", base.DEC) + local f_pointed_type = ProtoField.uint8(abbr.."pointed_version", + "Pointed Thing Type", base.DEC, vs_pointed_type) + local f_pointed_under_x = ProtoField.int16(abbr.."pointed_under_x", + "Node position (under surface) X") + local f_pointed_under_y = ProtoField.int16(abbr.."pointed_under_y", + "Node position (under surface) Y") + local f_pointed_under_z = ProtoField.int16(abbr.."pointed_under_z", + "Node position (under surface) Z") + local f_pointed_above_x = ProtoField.int16(abbr.."pointed_above_x", + "Node position (above surface) X") + local f_pointed_above_y = ProtoField.int16(abbr.."pointed_above_y", + "Node position (above surface) Y") + local f_pointed_above_z = ProtoField.int16(abbr.."pointed_above_z", + "Node position (above surface) Z") + local f_pointed_object_id = ProtoField.int16(abbr.."pointed_object_id", + "Object ID") + -- mising: additional playerpos data just like in TOSERVER_PLAYERPOS + + minetest_client_commands[0x39] = { + "INTERACT", 11, + { f_action, + f_item, + f_plen, + f_pointed_version, + f_pointed_type, + f_pointed_under_x, + f_pointed_under_y, + f_pointed_under_z, + f_pointed_above_x, + f_pointed_above_y, + f_pointed_above_z, + f_pointed_object_id }, + function(buffer, pinfo, tree, t) + t:add(f_action, buffer(2,1)) + t:add(f_item, buffer(3,2)) + t:add(f_plen, buffer(5,4)) + local plen = buffer(5,4):uint() + if minetest_check_length(buffer, 9 + plen, t) then + t:add(f_pointed_version, buffer(9,1)) + t:add(f_pointed_type, buffer(10,1)) + local ptype = buffer(10,1):uint() + if ptype == 1 then -- Node + t:add(f_pointed_under_x, buffer(11,2)) + t:add(f_pointed_under_y, buffer(13,2)) + t:add(f_pointed_under_z, buffer(15,2)) + t:add(f_pointed_above_x, buffer(17,2)) + t:add(f_pointed_above_x, buffer(19,2)) + t:add(f_pointed_above_x, buffer(21,2)) + elseif ptype == 2 then -- Object + t:add(f_pointed_object_id, buffer(11,2)) + end + end + end + } +end + +-- ... + +minetest_client_commands[0x3a] = { "REMOVED_SOUNDS", 2 } +minetest_client_commands[0x3b] = { "NODEMETA_FIELDS", 2 } +minetest_client_commands[0x3c] = { "INVENTORY_FIELDS", 2 } +minetest_client_commands[0x40] = { "REQUEST_MEDIA", 2 } +minetest_client_commands[0x41] = { "RECEIVED_MEDIA", 2 } + +-- TOSERVER_BREATH (obsolete) + +minetest_client_commands[0x42] = { "BREATH", 2 } +minetest_client_obsolete[0x42] = true + +-- TOSERVER_CLIENT_READY + +do + local abbr = "minetest.client.client_ready_" + local f_major = ProtoField.uint8(abbr.."major","Version Major") + local f_minor = ProtoField.uint8(abbr.."minor","Version Minor") + local f_patch = ProtoField.uint8(abbr.."patch","Version Patch") + local f_reserved = ProtoField.uint8(abbr.."reserved","Reserved") + local f_versionlen, f_version = + minetest_field_helper("uint16", abbr.."version", "Full Version String") + local f_formspec_ver = ProtoField.uint16(abbr.."formspec_version", + "Formspec API version") + + minetest_client_commands[0x43] = { + "CLIENT_READY", + 8, + { f_major, f_minor, f_patch, f_reserved, f_versionlen, + f_version, f_formspec_ver }, + function(buffer, pinfo, tree, t) + t:add(f_major, buffer(2,1)) + t:add(f_minor, buffer(3,1)) + t:add(f_patch, buffer(4,1)) + t:add(f_reserved, buffer(5,1)) + local off = minetest_decode_helper_ascii(buffer, t, "uint16", 6, + f_versionlen, f_version) + if off and minetest_check_length(buffer, off + 2, t) then + t:add(f_formspec_ver, buffer(off,2)) + end + end + } +end + +-- ... + +minetest_client_commands[0x50] = { "FIRST_SRP", 2 } +minetest_client_commands[0x51] = { "SRP_BYTES_A", 2 } +minetest_client_commands[0x52] = { "SRP_BYTES_M", 2 } + + + +-------------------------------------------- +-- Part 3 -- +-- Server command dissectors (TOCLIENT_*) -- +-------------------------------------------- + +minetest_server_commands = {} +minetest_server_obsolete = {} + +-- TOCLIENT_HELLO + +do + local abbr = "minetest.server.hello_" + + local f_ser_fmt = ProtoField.uint8(abbr.."ser_version", + "Deployed serialization format version", base.DEC) + local f_comp_mode = ProtoField.uint16(abbr.."compression", + "Deployed compression mode", base.DEC, { [0] = "No compression" }) + local f_proto = ProtoField.uint16(abbr.."proto", + "Deployed protocol version", base.DEC) + local f_auth_methods = ProtoField.bytes(abbr.."auth_modes", + "Supported authentication modes") + local f_legacy_namelen, f_legacy_name = minetest_field_helper("uint16", + abbr.."legacy_name", "Legacy player name for hashing") + + minetest_server_commands[0x02] = { + "HELLO", + 13, + { f_ser_fmt, f_comp_mode, f_proto, f_auth_methods, + f_legacy_namelen, f_legacy_name }, + function(buffer, pinfo, tree, t) + t:add(f_ser_fmt, buffer(2,1)) + t:add(f_comp_mode, buffer(3,2)) + t:add(f_proto, buffer(5,2)) + t:add(f_auth_methods, buffer(7,4)) + minetest_decode_helper_ascii(buffer, t, "uint16", 11, f_legacy_namelen, f_legacy_name) + end + } +end + +-- TOCLIENT_AUTH_ACCEPT + +do + local abbr = "minetest.server.auth_accept_" + + local f_player_x = ProtoField.float(abbr.."player_x", "Player position X") + local f_player_y = ProtoField.float(abbr.."player_y", "Player position Y") + local f_player_z = ProtoField.float(abbr.."player_z", "Player position Z") + local f_map_seed = ProtoField.uint64(abbr.."map_seed", "Map seed") + local f_send_interval = ProtoField.float(abbr.."send_interval", + "Recommended send interval") + local f_sudo_auth_methods = ProtoField.bytes(abbr.."sudo_auth_methods", + "Supported auth methods for sudo mode") + + minetest_server_commands[0x03] = { + "AUTH_ACCEPT", + 30, + { f_player_x, f_player_y, f_player_z, f_map_seed, + f_send_interval, f_sudo_auth_methods }, + function(buffer, pinfo, tree, t) + t:add(f_player_x, buffer(2,4)) + t:add(f_player_y, buffer(6,4)) + t:add(f_player_z, buffer(10,4)) + t:add(f_map_seed, buffer(14,8)) + t:add(f_send_interval, buffer(22,4)) + t:add(f_sudo_auth_methods, buffer(26,4)) + end + } +end + +-- ... + +minetest_server_commands[0x04] = {"ACCEPT_SUDO_MODE", 2} +minetest_server_commands[0x05] = {"DENY_SUDO_MODE", 2} +minetest_server_commands[0x0A] = {"ACCESS_DENIED", 2} + +-- TOCLIENT_INIT (obsolete) + +minetest_server_commands[0x10] = { "INIT", 2 } +minetest_server_obsolete[0x10] = true + +-- TOCLIENT_BLOCKDATA + +do + local f_x = ProtoField.int16("minetest.server.blockdata_x", "Block position X", base.DEC) + local f_y = ProtoField.int16("minetest.server.blockdata_y", "Block position Y", base.DEC) + local f_z = ProtoField.int16("minetest.server.blockdata_z", "Block position Z", base.DEC) + local f_data = ProtoField.bytes("minetest.server.blockdata_block", "Serialized MapBlock") + + minetest_server_commands[0x20] = { + "BLOCKDATA", 8, + { f_x, f_y, f_z, f_data }, + function(buffer, pinfo, tree, t) + t:add(f_x, buffer(2,2)) + t:add(f_y, buffer(4,2)) + t:add(f_z, buffer(6,2)) + t:add(f_data, buffer(8, buffer:len() - 8)) + end + } +end + +-- TOCLIENT_ADDNODE + +do + local f_x = ProtoField.int16("minetest.server.addnode_x", "Position X", base.DEC) + local f_y = ProtoField.int16("minetest.server.addnode_y", "Position Y", base.DEC) + local f_z = ProtoField.int16("minetest.server.addnode_z", "Position Z", base.DEC) + local f_data = ProtoField.bytes("minetest.server.addnode_node", "Serialized MapNode") + + minetest_server_commands[0x21] = { + "ADDNODE", 8, + { f_x, f_y, f_z, f_data }, + function(buffer, pinfo, tree, t) + t:add(f_x, buffer(2,2)) + t:add(f_y, buffer(4,2)) + t:add(f_z, buffer(6,2)) + t:add(f_data, buffer(8, buffer:len() - 8)) + end + } +end + +-- TOCLIENT_REMOVENODE + +do + local f_x = ProtoField.int16("minetest.server.removenode_x", "Position X", base.DEC) + local f_y = ProtoField.int16("minetest.server.removenode_y", "Position Y", base.DEC) + local f_z = ProtoField.int16("minetest.server.removenode_z", "Position Z", base.DEC) + + minetest_server_commands[0x22] = { + "REMOVENODE", 8, + { f_x, f_y, f_z }, + function(buffer, pinfo, tree, t) + t:add(f_x, buffer(2,2)) + t:add(f_y, buffer(4,2)) + t:add(f_z, buffer(6,2)) + end + } +end + +-- TOCLIENT_PLAYERPOS (obsolete) + +minetest_server_commands[0x23] = { "PLAYERPOS", 2 } +minetest_server_obsolete[0x23] = true + +-- TOCLIENT_PLAYERINFO (obsolete) + +minetest_server_commands[0x24] = { "PLAYERINFO", 2 } +minetest_server_obsolete[0x24] = true + +-- TOCLIENT_OPT_BLOCK_NOT_FOUND (obsolete) + +minetest_server_commands[0x25] = { "OPT_BLOCK_NOT_FOUND", 2 } +minetest_server_obsolete[0x25] = true + +-- TOCLIENT_SECTORMETA (obsolete) + +minetest_server_commands[0x26] = { "SECTORMETA", 2 } +minetest_server_obsolete[0x26] = true + +-- TOCLIENT_INVENTORY + +do + local f_inventory = ProtoField.string("minetest.server.inventory", "Inventory") + + minetest_server_commands[0x27] = { + "INVENTORY", 2, + { f_inventory }, + function(buffer, pinfo, tree, t) + t:add(f_inventory, buffer(2, buffer:len() - 2)) + end + } +end + +-- TOCLIENT_OBJECTDATA (obsolete) + +minetest_server_commands[0x28] = { "OBJECTDATA", 2 } +minetest_server_obsolete[0x28] = true + +-- TOCLIENT_TIME_OF_DAY + +do + local f_time = ProtoField.uint16("minetest.server.time_of_day", "Time", base.DEC) + local f_time_speed = ProtoField.float("minetest.server.time_speed", "Time Speed", base.DEC) + + minetest_server_commands[0x29] = { + "TIME_OF_DAY", 4, + { f_time, f_time_speed }, + function(buffer, pinfo, tree, t) + t:add(f_time, buffer(2,2)) + t:add(f_time_speed, buffer(4,4)) + end + } +end + +-- TOCLIENT_CSM_RESTRICTION_FLAGS + +minetest_server_commands[0x2a] = { "CSM_RESTRICTION_FLAGS", 2 } + +-- TOCLIENT_PLAYER_SPEED + +minetest_server_commands[0x2b] = { "PLAYER_SPEED", 2 } + +-- TOCLIENT_CHAT_MESSAGE + +do + local abbr = "minetest.server.chat_message_" + local vs_type = { + [0] = "Raw", + [1] = "Normal", + [2] = "Announce", + [3] = "System", + } + + local f_version = ProtoField.uint8(abbr.."version", "Version") + local f_type = ProtoField.uint8(abbr.."type", "Message Type", base.DEC, vs_type) + local f_senderlen, f_sender = minetest_field_helper("uint16", abbr.."sender", + "Message sender") + local f_messagelen, f_message = minetest_field_helper("uint16", abbr:sub(1,-2), + "Message") + + minetest_server_commands[0x2f] = { + "CHAT_MESSAGE", 8, + { f_version, f_type, f_senderlen, f_sender, + f_messagelen, f_message }, + function(buffer, pinfo, tree, t) + t:add(f_version, buffer(2,1)) + t:add(f_type, buffer(3,1)) + local off = 4 + off = minetest_decode_helper_utf16(buffer, t, "uint16", off, f_senderlen, f_sender) + if off then + off = minetest_decode_helper_utf16(buffer, t, "uint16", off, f_messagelen, f_message) + end + end + } +end + +-- TOCLIENT_CHAT_MESSAGE_OLD (obsolete) + +minetest_server_commands[0x30] = { "CHAT_MESSAGE_OLD", 2 } +minetest_server_obsolete[0x30] = true + +-- TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD + +do + local f_removed_count = ProtoField.uint16( + "minetest.server.active_object_remove_add_removed_count", + "Count of removed objects", base.DEC) + local f_removed = ProtoField.bytes( + "minetest.server.active_object_remove_add_removed", + "Removed object") + local f_removed_id = ProtoField.uint16( + "minetest.server.active_object_remove_add_removed_id", + "ID", base.DEC) + + local f_added_count = ProtoField.uint16( + "minetest.server.active_object_remove_add_added_count", + "Count of added objects", base.DEC) + local f_added = ProtoField.bytes( + "minetest.server.active_object_remove_add_added", + "Added object") + local f_added_id = ProtoField.uint16( + "minetest.server.active_object_remove_add_added_id", + "ID", base.DEC) + local f_added_type = ProtoField.uint8( + "minetest.server.active_object_remove_add_added_type", + "Type", base.DEC) + local f_added_init_length = ProtoField.uint32( + "minetest.server.active_object_remove_add_added_init_length", + "Initialization data length", base.DEC) + local f_added_init_data = ProtoField.bytes( + "minetest.server.active_object_remove_add_added_init_data", + "Initialization data") + + minetest_server_commands[0x31] = { + "ACTIVE_OBJECT_REMOVE_ADD", 6, + { f_removed_count, f_removed, f_removed_id, + f_added_count, f_added, f_added_id, + f_added_type, f_added_init_length, f_added_init_data }, + function(buffer, pinfo, tree, t) + local t2, index, pos + + local removed_count_pos = 2 + local removed_count = buffer(removed_count_pos, 2):uint() + t:add(f_removed_count, buffer(removed_count_pos, 2)) + + local added_count_pos = removed_count_pos + 2 + 2 * removed_count + if not minetest_check_length(buffer, added_count_pos + 2, t) then + return + end + + -- Loop through removed active objects + for index = 0, removed_count - 1 do + pos = removed_count_pos + 2 + 2 * index + t2 = t:add(f_removed, buffer(pos, 2)) + t2:set_text("Removed object, ID = " .. buffer(pos, 2):uint()) + t2:add(f_removed_id, buffer(pos, 2)) + end + + local added_count = buffer(added_count_pos, 2):uint() + t:add(f_added_count, buffer(added_count_pos, 2)) + + -- Loop through added active objects + pos = added_count_pos + 2 + for index = 0, added_count - 1 do + if not minetest_check_length(buffer, pos + 7, t) then + return + end + + local init_length = buffer(pos + 3, 4):uint() + if not minetest_check_length(buffer, pos + 7 + init_length, t) then + return + end + + t2 = t:add(f_added, buffer(pos, 7 + init_length)) + t2:set_text("Added object, ID = " .. buffer(pos, 2):uint()) + t2:add(f_added_id, buffer(pos, 2)) + t2:add(f_added_type, buffer(pos + 2, 1)) + t2:add(f_added_init_length, buffer(pos + 3, 4)) + t2:add(f_added_init_data, buffer(pos + 7, init_length)) + + pos = pos + 7 + init_length + end + + pinfo.cols.info:append(" * " .. (removed_count + added_count)) + end + } +end + +-- TOCLIENT_ACTIVE_OBJECT_MESSAGES + +do + local f_object_count = ProtoField.uint16( + "minetest.server.active_object_messages_object_count", + "Count of objects", base.DEC) + local f_object = ProtoField.bytes( + "minetest.server.active_object_messages_object", + "Object") + local f_object_id = ProtoField.uint16( + "minetest.server.active_object_messages_id", + "ID", base.DEC) + local f_message_length = ProtoField.uint16( + "minetest.server.active_object_messages_message_length", + "Message length", base.DEC) + local f_message = ProtoField.bytes( + "minetest.server.active_object_messages_message", + "Message") + + minetest_server_commands[0x32] = { + "ACTIVE_OBJECT_MESSAGES", 2, + { f_object_count, f_object, f_object_id, f_message_length, f_message }, + function(buffer, pinfo, tree, t) + local t2, count, pos, message_length + + count = 0 + pos = 2 + while pos < buffer:len() do + if not minetest_check_length(buffer, pos + 4, t) then + return + end + message_length = buffer(pos + 2, 2):uint() + if not minetest_check_length(buffer, pos + 4 + message_length, t) then + return + end + count = count + 1 + pos = pos + 4 + message_length + end + + pinfo.cols.info:append(" * " .. count) + t:add(f_object_count, count):set_generated() + + pos = 2 + while pos < buffer:len() do + message_length = buffer(pos + 2, 2):uint() + + t2 = t:add(f_object, buffer(pos, 4 + message_length)) + t2:set_text("Object, ID = " .. buffer(pos, 2):uint()) + t2:add(f_object_id, buffer(pos, 2)) + t2:add(f_message_length, buffer(pos + 2, 2)) + t2:add(f_message, buffer(pos + 4, message_length)) + + pos = pos + 4 + message_length + end + end + } +end + +-- TOCLIENT_HP + +do + local f_hp = ProtoField.uint16("minetest.server.hp", "Hitpoints", base.DEC) + + minetest_server_commands[0x33] = { + "HP", 4, + { f_hp }, + function(buffer, pinfo, tree, t) + t:add(f_hp, buffer(2,2)) + end + } +end + +-- TOCLIENT_MOVE_PLAYER + +do + local abbr = "minetest.server.move_player_" + + local f_x = ProtoField.float(abbr.."x", "Position X") + local f_y = ProtoField.float(abbr.."y", "Position Y") + local f_z = ProtoField.float(abbr.."z", "Position Z") + local f_pitch = ProtoField.float(abbr.."_pitch", "Pitch") + local f_yaw = ProtoField.float(abbr.."yaw", "Yaw") + + minetest_server_commands[0x34] = { + "MOVE_PLAYER", 22, + { f_x, f_y, f_z, f_pitch, f_yaw, f_garbage }, + function(buffer, pinfo, tree, t) + t:add(f_x, buffer(2, 4)) + t:add(f_y, buffer(6, 4)) + t:add(f_z, buffer(10, 4)) + t:add(f_pitch, buffer(14, 4)) + t:add(f_yaw, buffer(18, 4)) + end + } +end + +-- TOCLIENT_ACCESS_DENIED_LEGACY + +do + local f_reason_length = ProtoField.uint16("minetest.server.access_denied_reason_length", "Reason length", base.DEC) + local f_reason = ProtoField.string("minetest.server.access_denied_reason", "Reason") + + minetest_server_commands[0x35] = { + "ACCESS_DENIED_LEGACY", 4, + { f_reason_length, f_reason }, + function(buffer, pinfo, tree, t) + t:add(f_reason_length, buffer(2,2)) + local reason_length = buffer(2,2):uint() + if minetest_check_length(buffer, 4 + reason_length * 2, t) then + t:add(f_reason, minetest_convert_utf16(buffer(4, reason_length * 2), "Converted reason message")) + end + end + } +end + +-- TOCLIENT_FOV + +minetest_server_commands[0x36] = { "FOV", 2 } + +-- TOCLIENT_DEATHSCREEN + +do + local f_set_camera_point_target = ProtoField.bool( + "minetest.server.deathscreen_set_camera_point_target", + "Set camera point target") + local f_camera_point_target_x = ProtoField.int32( + "minetest.server.deathscreen_camera_point_target_x", + "Camera point target X", base.DEC) + local f_camera_point_target_y = ProtoField.int32( + "minetest.server.deathscreen_camera_point_target_y", + "Camera point target Y", base.DEC) + local f_camera_point_target_z = ProtoField.int32( + "minetest.server.deathscreen_camera_point_target_z", + "Camera point target Z", base.DEC) + + minetest_server_commands[0x37] = { + "DEATHSCREEN", 15, + { f_set_camera_point_target, f_camera_point_target_x, + f_camera_point_target_y, f_camera_point_target_z}, + function(buffer, pinfo, tree, t) + t:add(f_set_camera_point_target, buffer(2,1)) + t:add(f_camera_point_target_x, buffer(3,4)) + t:add(f_camera_point_target_y, buffer(7,4)) + t:add(f_camera_point_target_z, buffer(11,4)) + end + } +end + +-- TOCLIENT_MEDIA + +minetest_server_commands[0x38] = {"MEDIA", 2} + +-- TOCLIENT_TOOLDEF (obsolete) + +minetest_server_commands[0x39] = {"TOOLDEF", 2} +minetest_server_obsolete[0x39] = true + +-- TOCLIENT_NODEDEF + +minetest_server_commands[0x3a] = {"NODEDEF", 2} + +-- TOCLIENT_CRAFTITEMDEF (obsolete) + +minetest_server_commands[0x3b] = {"CRAFTITEMDEF", 2} +minetest_server_obsolete[0x3b] = true + +-- ... + +minetest_server_commands[0x3c] = {"ANNOUNCE_MEDIA", 2} +minetest_server_commands[0x3d] = {"ITEMDEF", 2} +minetest_server_commands[0x3f] = {"PLAY_SOUND", 2} +minetest_server_commands[0x40] = {"STOP_SOUND", 2} +minetest_server_commands[0x41] = {"PRIVILEGES", 2} +minetest_server_commands[0x42] = {"INVENTORY_FORMSPEC", 2} +minetest_server_commands[0x43] = {"DETACHED_INVENTORY", 2} +minetest_server_commands[0x44] = {"SHOW_FORMSPEC", 2} +minetest_server_commands[0x45] = {"MOVEMENT", 2} +minetest_server_commands[0x46] = {"SPAWN_PARTICLE", 2} +minetest_server_commands[0x47] = {"ADD_PARTICLE_SPAWNER", 2} + +-- TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY (obsolete) + +minetest_server_commands[0x48] = {"DELETE_PARTICLESPAWNER_LEGACY", 2} +minetest_server_obsolete[0x48] = true + +-- ... + +minetest_server_commands[0x49] = {"HUDADD", 2} +minetest_server_commands[0x4a] = {"HUDRM", 2} +minetest_server_commands[0x4b] = {"HUDCHANGE", 2} +minetest_server_commands[0x4c] = {"HUD_SET_FLAGS", 2} +minetest_server_commands[0x4d] = {"HUD_SET_PARAM", 2} +minetest_server_commands[0x4e] = {"BREATH", 2} +minetest_server_commands[0x4f] = {"SET_SKY", 2} +minetest_server_commands[0x50] = {"OVERRIDE_DAY_NIGHT_RATIO", 2} +minetest_server_commands[0x51] = {"LOCAL_PLAYER_ANIMATIONS", 2} +minetest_server_commands[0x52] = {"EYE_OFFSET", 2} +minetest_server_commands[0x53] = {"DELETE_PARTICLESPAWNER", 2} +minetest_server_commands[0x54] = {"CLOUD_PARAMS", 2} +minetest_server_commands[0x55] = {"FADE_SOUND", 2} + +-- TOCLIENT_UPDATE_PLAYER_LIST + +do + local abbr = "minetest.server.update_player_list_" + local vs_type = { + [0] = "Init", + [1] = "Add", + [2] = "Remove", + } + + local f_type = ProtoField.uint8(abbr.."type", "Type", base.DEC, vs_type) + local f_count = ProtoField.uint16(abbr.."count", "Number of players", base.DEC) + local f_name = ProtoField.string(abbr.."name", "Name") + + minetest_server_commands[0x56] = { + "UPDATE_PLAYER_LIST", + 5, + { f_type, f_count, f_name }, + function(buffer, pinfo, tree, t) + t:add(f_type, buffer(2,1)) + t:add(f_count, buffer(3,2)) + local count = buffer(3,2):uint() + local off = 5 + for i = 1, count do + if not minetest_check_length(buffer, off + 2, t) then + return + end + off = minetest_decode_helper_ascii(buffer, t, "uint16", off, nil, f_name) + if not off then + return + end + end + end + } +end + +-- ... + +minetest_server_commands[0x57] = {"MODCHANNEL_MSG", 2} +minetest_server_commands[0x58] = {"MODCHANNEL_SIGNAL", 2} +minetest_server_commands[0x59] = {"NODEMETA_CHANGED", 2} +minetest_server_commands[0x5a] = {"SET_SUN", 2} +minetest_server_commands[0x5b] = {"SET_MOON", 2} +minetest_server_commands[0x5c] = {"SET_STARS", 2} +minetest_server_commands[0x60] = {"SRP_BYTES_S_B", 2} +minetest_server_commands[0x61] = {"FORMSPEC_PREPEND", 2} + + +------------------------------------ +-- Part 4 -- +-- Wrapper protocol subdissectors -- +------------------------------------ + +-- minetest.control dissector + +do + local p_control = Proto("minetest.control", "Minetest Control") + + local vs_control_type = { + [0] = "Ack", + [1] = "Set Peer ID", + [2] = "Ping", + [3] = "Disco" + } + + local f_control_type = ProtoField.uint8("minetest.control.type", "Control Type", base.DEC, vs_control_type) + local f_control_ack = ProtoField.uint16("minetest.control.ack", "ACK sequence number", base.DEC) + local f_control_peerid = ProtoField.uint8("minetest.control.peerid", "New peer ID", base.DEC) + p_control.fields = { f_control_type, f_control_ack, f_control_peerid } + + local data_dissector = Dissector.get("data") + + function p_control.dissector(buffer, pinfo, tree) + local t = tree:add(p_control, buffer(0,1)) + t:add(f_control_type, buffer(0,1)) + + pinfo.cols.info = "Control message" + + local pos = 1 + if buffer(0,1):uint() == 0 then + pos = 3 + t:set_len(3) + t:add(f_control_ack, buffer(1,2)) + pinfo.cols.info = "Ack " .. buffer(1,2):uint() + elseif buffer(0,1):uint() == 1 then + pos = 3 + t:set_len(3) + t:add(f_control_peerid, buffer(1,2)) + pinfo.cols.info = "Set peer ID " .. buffer(1,2):uint() + elseif buffer(0,1):uint() == 2 then + pinfo.cols.info = "Ping" + elseif buffer(0,1):uint() == 3 then + pinfo.cols.info = "Disco" + end + + data_dissector:call(buffer(pos):tvb(), pinfo, tree) + end +end + +-- minetest.client dissector +-- minetest.server dissector + +-- Defines the minetest.client or minetest.server Proto. These two protocols +-- are created by the same function because they are so similar. +-- Parameter: proto: the Proto object +-- Parameter: this_peer: "Client" or "Server" +-- Parameter: other_peer: "Server" or "Client" +-- Parameter: commands: table of command information, built above +-- Parameter: obsolete: table of obsolete commands, built above +function minetest_define_client_or_server_proto(is_client) + -- Differences between minetest.client and minetest.server + local proto_name, this_peer, other_peer, empty_message_info + local commands, obsolete + if is_client then + proto_name = "minetest.client" + this_peer = "Client" + other_peer = "Server" + empty_message_info = "Empty message / Connect" + commands = minetest_client_commands -- defined in Part 2 + obsolete = minetest_client_obsolete -- defined in Part 2 + else + proto_name = "minetest.server" + this_peer = "Server" + other_peer = "Client" + empty_message_info = "Empty message" + commands = minetest_server_commands -- defined in Part 3 + obsolete = minetest_server_obsolete -- defined in Part 3 + end + + -- Create the protocol object. + local proto = Proto(proto_name, "Minetest " .. this_peer .. " to " .. other_peer) + + -- Create a table vs_command that maps command codes to command names. + local vs_command = {} + local code, command_info + for code, command_info in pairs(commands) do + local command_name = command_info[1] + vs_command[code] = "TO" .. other_peer:upper() .. "_" .. command_name + end + + -- Field definitions + local f_command = ProtoField.uint16(proto_name .. ".command", "Command", base.HEX, vs_command) + local f_empty = ProtoField.bool(proto_name .. ".empty", "Is empty", BASE_NONE) + proto.fields = { f_command, f_empty } + + -- Add command-specific fields to the protocol + for code, command_info in pairs(commands) do + local command_fields = command_info[3] + if command_fields ~= nil then + for index, field in ipairs(command_fields) do + assert(field ~= nil) + table.insert(proto.fields, field) + end + end + end + + -- minetest.client or minetest.server dissector function + function proto.dissector(buffer, pinfo, tree) + local t = tree:add(proto, buffer) + + pinfo.cols.info = this_peer + + if buffer:len() == 0 then + -- Empty message. + t:add(f_empty, 1):set_generated() + pinfo.cols.info:append(": " .. empty_message_info) + + elseif minetest_check_length(buffer, 2, t) then + -- Get the command code. + t:add(f_command, buffer(0,2)) + local code = buffer(0,2):uint() + local command_info = commands[code] + if command_info == nil then + -- Error: Unknown command. + pinfo.cols.info:append(": Unknown command") + t:add_expert_info(PI_UNDECODED, PI_WARN, "Unknown " .. this_peer .. " to " .. other_peer .. " command") + else + -- Process a known command + local command_name = command_info[1] + local command_min_length = command_info[2] + local command_fields = command_info[3] + local command_dissector = command_info[4] + if minetest_check_length(buffer, command_min_length, t) then + pinfo.cols.info:append(": " .. command_name) + if command_dissector ~= nil then + command_dissector(buffer, pinfo, tree, t) + end + end + if obsolete[code] then + t:add_expert_info(PI_REQUEST_CODE, PI_WARN, "Obsolete command.") + end + end + end + end +end + +minetest_define_client_or_server_proto(true) -- minetest.client +minetest_define_client_or_server_proto(false) -- minetest.server + +-- minetest.split dissector + +do + local p_split = Proto("minetest.split", "Minetest Split Message") + + local f_split_seq = ProtoField.uint16("minetest.split.seq", "Sequence number", base.DEC) + local f_split_chunkcount = ProtoField.uint16("minetest.split.chunkcount", "Chunk count", base.DEC) + local f_split_chunknum = ProtoField.uint16("minetest.split.chunknum", "Chunk number", base.DEC) + local f_split_data = ProtoField.bytes("minetest.split.data", "Split message data") + p_split.fields = { f_split_seq, f_split_chunkcount, f_split_chunknum, f_split_data } + + function p_split.dissector(buffer, pinfo, tree) + local t = tree:add(p_split, buffer(0,6)) + t:add(f_split_seq, buffer(0,2)) + t:add(f_split_chunkcount, buffer(2,2)) + t:add(f_split_chunknum, buffer(4,2)) + t:add(f_split_data, buffer(6)) + pinfo.cols.info:append(" " .. buffer(0,2):uint() .. " chunk " .. buffer(4,2):uint() .. "/" .. buffer(2,2):uint()) + end +end + + + + +------------------------------------- +-- Part 5 -- +-- Wrapper protocol main dissector -- +------------------------------------- + +-- minetest dissector + +do + local p_minetest = Proto("minetest", "Minetest") + + local minetest_id = 0x4f457403 + local vs_id = { + [minetest_id] = "Valid" + } + + local vs_peer = { + [0] = "Inexistent", + [1] = "Server" + } + + local vs_type = { + [0] = "Control", + [1] = "Original", + [2] = "Split", + [3] = "Reliable" + } + + local f_id = ProtoField.uint32("minetest.id", "ID", base.HEX, vs_id) + local f_peer = ProtoField.uint16("minetest.peer", "Peer", base.DEC, vs_peer) + local f_channel = ProtoField.uint8("minetest.channel", "Channel", base.DEC) + local f_type = ProtoField.uint8("minetest.type", "Type", base.DEC, vs_type) + local f_seq = ProtoField.uint16("minetest.seq", "Sequence number", base.DEC) + local f_subtype = ProtoField.uint8("minetest.subtype", "Subtype", base.DEC, vs_type) + + p_minetest.fields = { f_id, f_peer, f_channel, f_type, f_seq, f_subtype } + + local data_dissector = Dissector.get("data") + local control_dissector = Dissector.get("minetest.control") + local client_dissector = Dissector.get("minetest.client") + local server_dissector = Dissector.get("minetest.server") + local split_dissector = Dissector.get("minetest.split") + + function p_minetest.dissector(buffer, pinfo, tree) + + -- Add Minetest tree item and verify the ID + local t = tree:add(p_minetest, buffer(0,8)) + t:add(f_id, buffer(0,4)) + if buffer(0,4):uint() ~= minetest_id then + t:add_expert_info(PI_UNDECODED, PI_WARN, "Invalid ID, this is not a Minetest packet") + return + end + + -- ID is valid, so replace packet's shown protocol + pinfo.cols.protocol = "Minetest" + pinfo.cols.info = "Minetest" + + -- Set the other header fields + t:add(f_peer, buffer(4,2)) + t:add(f_channel, buffer(6,1)) + t:add(f_type, buffer(7,1)) + t:set_text("Minetest, Peer: " .. buffer(4,2):uint() .. ", Channel: " .. buffer(6,1):uint()) + + local reliability_info + if buffer(7,1):uint() == 3 then + -- Reliable message + reliability_info = "Seq=" .. buffer(8,2):uint() + t:set_len(11) + t:add(f_seq, buffer(8,2)) + t:add(f_subtype, buffer(10,1)) + pos = 10 + else + -- Unreliable message + reliability_info = "Unrel" + pos = 7 + end + + if buffer(pos,1):uint() == 0 then + -- Control message, possibly reliable + control_dissector:call(buffer(pos+1):tvb(), pinfo, tree) + elseif buffer(pos,1):uint() == 1 then + -- Original message, possibly reliable + if buffer(4,2):uint() == 1 then + server_dissector:call(buffer(pos+1):tvb(), pinfo, tree) + else + client_dissector:call(buffer(pos+1):tvb(), pinfo, tree) + end + elseif buffer(pos,1):uint() == 2 then + -- Split message, possibly reliable + if buffer(4,2):uint() == 1 then + pinfo.cols.info = "Server: Split message" + else + pinfo.cols.info = "Client: Split message" + end + split_dissector:call(buffer(pos+1):tvb(), pinfo, tree) + elseif buffer(pos,1):uint() == 3 then + -- Doubly reliable message?? + t:add_expert_info(PI_MALFORMED, PI_ERROR, "Reliable message wrapped in reliable message") + else + data_dissector:call(buffer(pos+1):tvb(), pinfo, tree) + end + + pinfo.cols.info:append(" (" .. reliability_info .. ")") + + end + + -- FIXME Is there a way to let the dissector table check if the first payload bytes are 0x4f457403? + DissectorTable.get("udp.port"):add(30000, p_minetest) + DissectorTable.get("udp.port"):add(30001, p_minetest) +end + + + + +------------------------------ +-- Part 6 -- +-- Utility functions part 2 -- +------------------------------ + +-- Checks if a (sub-)Tvb is long enough to be further dissected. +-- If it is long enough, sets the dissector tree item length to min_len +-- and returns true. If it is not long enough, adds expert info to the +-- dissector tree and returns false. +-- Parameter: tvb: the Tvb +-- Parameter: min_len: required minimum length +-- Parameter: t: dissector tree item +-- Returns: true if tvb:len() >= min_len, false otherwise +function minetest_check_length(tvb, min_len, t) + if tvb:len() >= min_len then + t:set_len(min_len) + return true + + -- TODO: check if other parts of + -- the dissector could benefit from reported_length_remaining + elseif tvb:reported_length_remaining() >= min_len then + t:add_expert_info(PI_UNDECODED, PI_INFO, "Only part of this packet was captured, unable to decode.") + return false + + else + t:add_expert_info(PI_MALFORMED, PI_ERROR, "Message is too short") + return false + end +end + +-- Takes a Tvb or TvbRange (i.e. part of a packet) that +-- contains a UTF-16 string and returns a TvbRange containing +-- string converted to ASCII. Any characters outside the range +-- 0x20 to 0x7e are replaced by a question mark. +-- Parameter: tvb: Tvb or TvbRange that contains the UTF-16 data +-- Parameter: name: will be the name of the newly created Tvb. +-- Returns: New TvbRange containing the ASCII string. +-- TODO: Handle surrogates (should only produce one question mark) +-- TODO: Remove this when Wireshark supports UTF-16 strings natively. +function minetest_convert_utf16(tvb, name) + local hex, pos, char + hex = "" + for pos = 0, tvb:len() - 2, 2 do + char = tvb(pos, 2):uint() + if (char >= 0x20 and char <= 0x7e) or char == 0x0a then + hex = hex .. string.format(" %02x", char) + else + hex = hex .. " 3F" + end + end + if hex == "" then + -- This is a hack to avoid a failed assertion in tvbuff.c + -- (function: ensure_contiguous_no_exception) + return ByteArray.new("00"):tvb(name):range(0,0) + else + return ByteArray.new(hex):tvb(name):range() + end +end + +-- Decodes a variable-length string as ASCII text +-- t_textlen, t_text should be the ProtoFields created by minetest_field_helper +-- alternatively t_text can be a ProtoField.string and t_textlen can be nil +-- lentype must be the type of the length field (as passed to minetest_field_helper) +-- returns nil if length check failed +function minetest_decode_helper_ascii(tvb, t, lentype, offset, f_textlen, f_text) + local n = ({uint16 = 2, uint32 = 4})[lentype] + assert(n) + + if f_textlen then + t:add(f_textlen, tvb(offset, n)) + end + local textlen = tvb(offset, n):uint() + if minetest_check_length(tvb, offset + n + textlen, t) then + t:add(f_text, tvb(offset + n, textlen)) + return offset + n + textlen + end +end + +-- Decodes a variable-length string as UTF-16 text +-- (see minetest_decode_helper_ascii) +function minetest_decode_helper_utf16(tvb, t, lentype, offset, f_textlen, f_text) + local n = ({uint16 = 2, uint32 = 4})[lentype] + assert(n) + + if f_textlen then + t:add(f_textlen, tvb(offset, n)) + end + local textlen = tvb(offset, n):uint() * 2 + if minetest_check_length(tvb, offset + n + textlen, t) then + t:add(f_text, minetest_convert_utf16(tvb(offset + n, textlen), "UTF-16 text")) + return offset + n + textlen + end +end