diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3b5ae35c..2cb22358 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,13 +52,13 @@ jobs: - name: Build on Linux if: startsWith(matrix.os, 'ubuntu') run: | - schroot --chroot steamrt_scout_i386 -- cmake -B build -S . -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DCMAKE_INSTALL_PREFIX="$PWD/dist" + schroot --chroot steamrt_scout_i386 -- cmake -DCMAKE_BUILD_TYPE=Release -DPOLLY=ON -B build -S . -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DCMAKE_INSTALL_PREFIX="$PWD/dist" schroot --chroot steamrt_scout_i386 -- cmake --build build --target all schroot --chroot steamrt_scout_i386 -- cmake --build build --target install - name: Build on Linux with vgui if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.cc, 'gcc') run: | - schroot --chroot steamrt_scout_i386 -- cmake -B build-vgui -S . -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VGUI=ON -DCMAKE_INSTALL_PREFIX="$PWD/dist-vgui" + schroot --chroot steamrt_scout_i386 -- cmake -DCMAKE_BUILD_TYPE=Release -DPOLLY=ON -B build-vgui -S . -DCMAKE_EXE_LINKER_FLAGS="-Wl,--no-undefined" -DUSE_VGUI=ON -DCMAKE_INSTALL_PREFIX="$PWD/dist-vgui" cp vgui_support/vgui-dev/lib/vgui.so build-vgui/cl_dll schroot --chroot steamrt_scout_i386 -- cmake --build build-vgui --target all schroot --chroot steamrt_scout_i386 -- cmake --build build-vgui --target install diff --git a/.gitignore b/.gitignore index 42594b50..2c5017bf 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,13 @@ CMakeSettings.json CMakeFiles CMakeCache.txt Makefile + +# Android Studio/Gradle +.gradle/ +.externalNativeBuild +.cxx/ +.idea/ +local.properties +.project +.classpath +.settings \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e2ea26c0..04cf5bce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") include(CheckIncludeFile) include(CheckCSourceCompiles) include(VSForceXPToolchain) # Force XP toolchain for Visual Studio +include(CheckIPOSupported) project (HLSDK-PORTABLE) @@ -46,16 +47,37 @@ option(USE_NOVGUI_SCOREBOARD "Prefer non-VGUI Scoreboard when USE_VGUI is enable option(USE_VOICEMGR "Enable VOICE MANAGER." OFF) option(BUILD_CLIENT "Build client dll" ON) option(BUILD_SERVER "Build server dll" ON) +option(POLLY "Enable pollyhedral optimization" OFF) -if (CMAKE_SIZEOF_VOID_P EQUAL 4 OR +if(CMAKE_SIZEOF_VOID_P EQUAL 4 OR ((WIN32 OR ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND (CMAKE_SYSTEM_PROCESSOR STREQUAL "x64" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "X64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" - OR CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64"))) + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "X86_64" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "EM64T"))) option(64BIT "Disable auto -m32 appending to compiler flags" OFF) - option(GOLDSOURCE_SUPPORT "Build goldsource compatible client library" ON) else() option(64BIT "Disable auto -m32 appending to compiler flags" ON) +endif() + +# It seems CMAKE_SYSTEM_PROCESSOR parameter completely useless for APPLE platform, +# so may need to set options here manually. +if((WIN32 OR ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + AND (((CMAKE_SYSTEM_PROCESSOR STREQUAL "x64" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "X64" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "X86_64" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "EM64T") AND NOT 64BIT) + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "X86" + OR CMAKE_SYSTEM_PROCESSOR STREQUAL "i386")) + option(GOLDSOURCE_SUPPORT "Build goldsource compatible client library" ON) +else() option(GOLDSOURCE_SUPPORT "Build goldsource compatible client library" OFF) endif() @@ -131,6 +153,13 @@ if(VITA) add_compile_options(-fno-use-cxa-atexit) endif() +check_ipo_supported(RESULT HAVE_LTO OUTPUT LTO_ERROR) +if(HAVE_LTO) + message(STATUS "IPO / LTO enabled") +else() + message(STATUS "IPO / LTO not supported: <${LTO_ERROR}>") +endif() + check_include_file("tgmath.h" HAVE_TGMATH_H) if(HAVE_TGMATH_H) if(NOT MSVC) @@ -157,3 +186,11 @@ endif() if(NOT BUILD_SERVER AND NOT BUILD_CLIENT) message(FATAL_ERROR "Nothing to build") endif() + +if(POLLY) + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_compile_options(-mllvm -polly) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + add_compile_options(-fgraphite-identity -floop-interchange -floop-block) + endif() +endif() diff --git a/README.md b/README.md index 706fa58a..3bff2f52 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ sudo ./setup_chroot.sh --i386 --tarball ./com.valvesoftware.SteamRuntime.Sdk-i38 Now you can use cmake and make prepending the commands with `schroot --chroot steamrt_scout_i386 --`: ``` -schroot --chroot steamrt_scout_i386 -- cmake -B build-in-steamrt -S . +schroot --chroot steamrt_scout_i386 -- cmake -DCMAKE_BUILD_TYPE=Release -B build-in-steamrt -S . schroot --chroot steamrt_scout_i386 -- cmake --build build-in-steamrt ``` @@ -180,13 +180,20 @@ sudo apt install cmake build-essential gcc-multilib g++-multilib libsdl2-dev:i38 ### Building ``` -cmake -B build -S . +cmake -DCMAKE_BUILD_TYPE=Release -B build -S . cmake --build build ``` Note that the libraries built this way might be not compatible with Steam Half-Life. If you have such issue you can configure it to build statically with c++ and gcc libraries: ``` -cmake .. -DCMAKE_C_FLAGS="-static-libstdc++ -static-libgcc" +cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -static-libstdc++ -static-libgcc" -B build -S . +cmake --build build +``` + +Alternatively, you can avoid libstdc++/libgcc_s linking using small libsupc++ library and optimization build flags instead(Really just set Release build type and set C compiler as C++ compiler): +``` +cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=cc -B build -S . +cmake --build build ``` To ensure portability it's still better to build using Steam Runtime or another chroot of some older distro. @@ -229,13 +236,36 @@ Insert your actual user name in place of `yourusername`. Prepend any make or cmake call with `schroot -c jessie --`: ``` -schroot --chroot jessie -- cmake -B build-in-chroot -S . +schroot --chroot jessie -- cmake -DCMAKE_BUILD_TYPE=Release -B build-in-chroot -S . schroot --chroot jessie -- cmake --build build-in-chroot ``` ## Android +1. Set up [Android Studio/Android SDK](https://developer.android.com/studio). -TODO +### Android Studio +Open the project located in the `android` folder and build. + +### Command-line +``` +cd android +./gradlew assembleRelease +``` + +### Customizing the build +settings.gradle: +* **rootProject.name** - project name displayed in Android Studio (optional). + +app/build.gradle: +* **android->namespace** and **android->defaultConfig->applicationId** - set both to desired package name. +* **getBuildNum** function - set **releaseDate** variable as desired. + +app/java/su/xash/hlsdk/MainActivity.java: +* **.putExtra("gamedir", ...)** - set desired gamedir. + +src/main/AndroidManifest.xml: +* **application->android:label** - set desired application name. +* **su.xash.engine.gamedir** value - set to same as above. ## Nintendo Switch @@ -307,7 +337,13 @@ Install C and C++ compilers (like gcc or clang), cmake and make. ### Building ``` -cmake -B build -S . +cmake -DCMAKE_BUILD_TYPE=Release -B build -S . +cmake --build build +``` + +Force 64-bit build: +``` +cmake -DCMAKE_BUILD_TYPE=Release -D64BIT=1 -B build -S . cmake --build build ``` @@ -316,15 +352,22 @@ cmake --build build To use waf, you need to install python (2.7 minimum) ``` -(./waf configure -T release) -(./waf) +./waf configure -T release +./waf +``` + +Force 64-bit build: +``` +./waf configure -T release -8 +./waf ``` ## Build options Some useful build options that can be set during the cmake step. -* **GOLDSOURCE_SUPPORT** - allows to turn off/on the support for GoldSource input. Set to **ON** by default on Windows and Linux, **OFF** on other platforms. +* **GOLDSOURCE_SUPPORT** - allows to turn off/on the support for GoldSource input. Set to **ON** by default on x86 Windows and x86 Linux, **OFF** on other platforms. +* **64BIT** - allows to turn off/on 64-bit build. Set to **OFF** by default on x86_64 Windows, x86_64 Linux and 32-bit platforms, **ON** on other 64-bit platforms. * **USE_VGUI** - whether to use VGUI library. **OFF** by default. You need to init `vgui_support` submodule in order to build with VGUI. This list is incomplete. Look at `CMakeLists.txt` to see all available options. diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 00000000..9952c3d1 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,73 @@ +import java.time.LocalDateTime +import java.time.Month +import java.time.temporal.ChronoUnit + +apply plugin: 'com.android.application' + +android { + ndkVersion '26.1.10909125' + namespace 'com.example.hlsdk' + + defaultConfig { + applicationId 'com.example.hlsdk' + versionName '1.0' + versionCode getBuildNum() + minSdkVersion 3 + targetSdk 34 + compileSdk 34 + + externalNativeBuild { + cmake { + arguments '-DPOLLY=ON' + } + } + } + + externalNativeBuild { + cmake { + version '3.22.1' + path file('../../CMakeLists.txt') + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + buildTypes { + debug { + minifyEnabled false + shrinkResources false + debuggable true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + release { + minifyEnabled false + shrinkResources false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + + lint { + abortOnError false + } + + androidResources { + noCompress += '' + } + + packagingOptions { + jniLibs { + useLegacyPackaging = true + } + } +} + +static def getBuildNum() { + LocalDateTime now = LocalDateTime.now() + LocalDateTime releaseDate = LocalDateTime.of(2023, Month.DECEMBER, 28, 0, 0, 0) + int qBuildNum = releaseDate.until(now, ChronoUnit.DAYS) + int minuteOfDay = now.getHour() * 60 + now.getMinute() + return qBuildNum * 10000 + minuteOfDay +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..d928f396 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/java/su/xash/hlsdk/MainActivity.java b/android/app/src/main/java/su/xash/hlsdk/MainActivity.java new file mode 100644 index 00000000..5d1dd353 --- /dev/null +++ b/android/app/src/main/java/su/xash/hlsdk/MainActivity.java @@ -0,0 +1,37 @@ +package su.xash.hlsdk; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; + +public class MainActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String pkg = "su.xash.engine.test"; + + try { + getPackageManager().getPackageInfo(pkg, 0); + } catch (PackageManager.NameNotFoundException e) { + try { + pkg = "su.xash.engine"; + getPackageManager().getPackageInfo(pkg, 0); + } catch (PackageManager.NameNotFoundException ex) { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=su.xash.engine")).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)); + finish(); + return; + } + } + + startActivity(new Intent().setComponent(new ComponentName(pkg, "su.xash.engine.XashActivity")) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) + .putExtra("gamedir", "valve") + .putExtra("gamelibdir", getApplicationInfo().nativeLibraryDir) + .putExtra("package", getPackageName())); + finish(); + } +} \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 00000000..61060cd6 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,17 @@ +buildscript { + repositories { + mavenCentral() + google() + } + + dependencies { + classpath 'com.android.tools.build:gradle:8.2.0' + } +} + +allprojects { + repositories { + mavenCentral() + google() + } +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 00000000..87cc72da --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,21 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=384m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# android.useDeprecatedNdk=true +android.enableJetifier=true +android.useAndroidX=true \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..2b338a93 Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..61656665 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Dec 28 14:36:02 EET 2023 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/android/gradlew b/android/gradlew new file mode 100755 index 00000000..9d82f789 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 00000000..8b31d676 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,3 @@ +include ':app' + +rootProject.name = 'hlsdk-portable' \ No newline at end of file diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index e12b2a13..e5fdfaa0 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -20,7 +20,7 @@ # SOFTWARE. # -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.9) project (CLDLL) set (CLDLL_LIBRARY client) @@ -29,13 +29,25 @@ add_definitions(-DCLIENT_DLL) if(NOT MSVC) add_compile_options(-fno-exceptions) # GCC/Clang flag - add_compile_options(-Wno-write-strings) # GCC/Clang flag + add_compile_options(-fno-rtti) # GCC/Clang flag add_compile_options(-fvisibility=hidden) # GCC/Clang flag add_definitions(-D_LINUX -DLINUX) # It seems enough for all non-Win32 systems add_definitions(-Dstricmp=strcasecmp -Dstrnicmp=strncasecmp) if(NOT MINGW) add_definitions(-D_snprintf=snprintf -D_vsnprintf=vsnprintf) endif() + if(CMAKE_BUILD_TYPE MATCHES "Release" + OR (CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo" + AND CMAKE_SYSTEM_NAME STREQUAL "Android")) + add_compile_options(-fno-unwind-tables -fno-asynchronous-unwind-tables) # GCC/Clang flag + add_compile_options(-fomit-frame-pointer) # GCC/Clang flag + add_compile_options(-ftree-vectorize) # GCC/Clang flag + add_compile_options(-funsafe-math-optimizations) # GCC/Clang flag + if(CMAKE_SYSTEM_NAME STREQUAL "Android") + add_compile_options(-O3 -DNDEBUG) # gradle compiles release builds with RelWithDebInfo(-O2 -g) and strips debug symbols. + target_link_options(${CLDLL_LIBRARY} PUBLIC "LINKER:-O3") + endif() + endif() else() add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) endif() @@ -219,8 +231,16 @@ if(MSVC) set_property(TARGET ${CLDLL_LIBRARY} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif() +if(HAVE_LTO) + set_property(TARGET ${CLDLL_LIBRARY} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) +endif() + install( TARGETS ${CLDLL_LIBRARY} DESTINATION "${GAMEDIR}/${CLIENT_INSTALL_DIR}/" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) + +add_custom_command(TARGET ${CLDLL_LIBRARY} + POST_BUILD DEPENDS ${CLDLL_LIBRARY} + COMMAND $<$:${CMAKE_STRIP}> -s $) diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h index 91615660..65275c69 100644 --- a/cl_dll/cl_util.h +++ b/cl_dll/cl_util.h @@ -166,7 +166,8 @@ void VectorScale( const float *in, float scale, float *out ); float VectorNormalize( float *v ); void VectorInverse( float *v ); -extern vec3_t vec3_origin; +// extern vec3_t vec3_origin; +extern float vec3_origin[3]; // disable 'possible loss of data converting float to int' warning message #pragma warning( disable: 4244 ) diff --git a/cl_dll/util.cpp b/cl_dll/util.cpp index 7d6b6669..ec5c796f 100644 --- a/cl_dll/util.cpp +++ b/cl_dll/util.cpp @@ -33,11 +33,11 @@ #if !defined(M_PI_F) #define M_PI_F (float)M_PI #endif -extern vec3_t vec3_origin; +// extern vec3_t vec3_origin; // if C++ mangling differs from C symbol name #if _MSC_VER || __WATCOMC__ -vec3_t vec3_origin; +float vec3_origin[3]; #endif float Length( const float *v ) diff --git a/dlls/CMakeLists.txt b/dlls/CMakeLists.txt index 5b5cd22a..afe449a7 100644 --- a/dlls/CMakeLists.txt +++ b/dlls/CMakeLists.txt @@ -20,17 +20,30 @@ # SOFTWARE. # -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.9) project (SVDLL) set (SVDLL_LIBRARY server) if(NOT MSVC) add_compile_options(-fno-exceptions) # GCC/Clang flag + add_compile_options(-fno-rtti) # GCC/Clang flag add_compile_options(-Wno-invalid-offsetof) # GCC/Clang flag add_compile_options(-fvisibility=hidden) # GCC/Clang flag add_definitions(-D_LINUX) # It seems enough for all non-Win32 systems add_definitions(-Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf ) + if(CMAKE_BUILD_TYPE MATCHES "Release" + OR (CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo" + AND CMAKE_SYSTEM_NAME STREQUAL "Android")) + add_compile_options(-fno-unwind-tables -fno-asynchronous-unwind-tables) # GCC/Clang flag + add_compile_options(-fomit-frame-pointer) # GCC/Clang flag + add_compile_options(-ftree-vectorize) # GCC/Clang flag + add_compile_options(-funsafe-math-optimizations) # GCC/Clang flag + if(CMAKE_SYSTEM_NAME STREQUAL "Android") + add_compile_options(-O3 -DNDEBUG) # gradle compiles release builds with RelWithDebInfo(-O2 -g) and strips debug symbols. + target_link_options(${SVDLL_LIBRARY} PUBLIC "LINKER:-O3") + endif() + endif() else() add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) endif() @@ -47,7 +60,6 @@ set (SVDLL_SOURCES gearbox/eagle.cpp gearbox/fgrunt.cpp gearbox/func_tank_of.cpp -# gearbox/gearbox_client.cpp gearbox/gearbox_effects.cpp gearbox/gearbox_triggers.cpp gearbox/gearbox_utils.cpp @@ -224,8 +236,16 @@ if(MSVC) set_property(TARGET ${SVDLL_LIBRARY} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif() +if(HAVE_LTO) + set_property(TARGET ${SVDLL_LIBRARY} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) +endif() + install( TARGETS ${SVDLL_LIBRARY} DESTINATION "${GAMEDIR}/${SERVER_INSTALL_DIR}/" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + +add_custom_command(TARGET ${SVDLL_LIBRARY} + POST_BUILD DEPENDS ${SVDLL_LIBRARY} + COMMAND $<$:${CMAKE_STRIP}> -s $) diff --git a/dlls/client.cpp b/dlls/client.cpp index 1e815ff7..c95cd17c 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -941,28 +941,6 @@ void ClientPrecache( void ) // Teleport sounds. Used by trigger_xen_return PRECACHE_SOUND( "debris/beamstart7.wav" ); - - PRECACHE_MODEL( "models/flag.mdl" ); - PRECACHE_MODEL( "models/civ_stand.mdl" ); - PRECACHE_MODEL( "models/mil_stand.mdl" ); - - PRECACHE_MODEL( "models/w_accelerator.mdl" ); - PRECACHE_MODEL( "models/w_backpack.mdl" ); - PRECACHE_MODEL( "models/w_fgrenade.mdl" ); - PRECACHE_MODEL( "models/w_health.mdl" ); - PRECACHE_MODEL( "models/w_icon.mdl" ); - PRECACHE_MODEL( "models/w_jumppack.mdl" ); - PRECACHE_MODEL( "models/w_porthev.mdl" ); - - PRECACHE_SOUND( "ctf/bm_flagtaken.wav" ); - PRECACHE_SOUND( "ctf/civ_flag_capture.wav" ); - PRECACHE_SOUND( "ctf/itemthrow.wav" ); - PRECACHE_SOUND( "ctf/marine_flag_capture.wav" ); - PRECACHE_SOUND( "ctf/pow_armor_charge.wav" ); - PRECACHE_SOUND( "ctf/pow_backpack.wav" ); - PRECACHE_SOUND( "ctf/pow_big_jump.wav" ); - PRECACHE_SOUND( "ctf/pow_health_charge.wav" ); - PRECACHE_SOUND( "ctf/soldier_flagtaken.wav" ); } /* diff --git a/dlls/game.cpp b/dlls/game.cpp index 033c1f19..051cc325 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -726,7 +726,7 @@ cvar_t sk_plr_spore3 = { "sk_plr_spore3", "0" }; void GameDLLInit( void ) { // Register cvars here: - if( CVAR_GET_POINTER( "build" ) ) + if( !CVAR_GET_POINTER( "sv_language" ) ) g_fIsXash3D = TRUE; g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); diff --git a/dlls/gearbox/ctf_gamerules.cpp b/dlls/gearbox/ctf_gamerules.cpp index 6c5c1608..05848eb3 100644 --- a/dlls/gearbox/ctf_gamerules.cpp +++ b/dlls/gearbox/ctf_gamerules.cpp @@ -200,8 +200,8 @@ void CCTFMultiplay::Think(void) frags_remaining = bestfrags; } - if (!g_bSpawnedRunes) - SpawnRunes(); + //if (!g_bSpawnedRunes) + // SpawnRunes(); if (m_flFlagStatusTime && m_flFlagStatusTime <= gpGlobals->time) GetFlagStatus(NULL); diff --git a/dlls/gearbox/ctf_powerups.cpp b/dlls/gearbox/ctf_powerups.cpp index 1bbbd66d..855ff348 100644 --- a/dlls/gearbox/ctf_powerups.cpp +++ b/dlls/gearbox/ctf_powerups.cpp @@ -114,12 +114,18 @@ void CPowerupCTFBase::Spawn(void) m_iszPrintName = ALLOC_STRING(printname); } - - SET_MODEL(ENT(pev), SelectRuneRandom(&m_iRuneFlag) ); + PRECACHE_MODEL("models/w_accelerator.mdl"); + PRECACHE_MODEL("models/w_backpack.mdl"); + PRECACHE_MODEL("models/w_health.mdl"); + PRECACHE_MODEL("models/w_jumppack.mdl"); + PRECACHE_MODEL("models/w_porthev.mdl"); + SET_MODEL(ENT(pev), modelname); } else { - SET_MODEL(ENT(pev), GetRuneModel()); + const char* modelname = GetRuneModel(); + PRECACHE_MODEL(modelname); + SET_MODEL(ENT(pev), modelname); m_iRuneFlag = GetRuneFlag(); } diff --git a/dlls/gearbox/gearbox_client.cpp b/dlls/gearbox/gearbox_client.cpp deleted file mode 100644 index c585e68e..00000000 --- a/dlls/gearbox/gearbox_client.cpp +++ /dev/null @@ -1,2096 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// Robin, 4-22-98: Moved set_suicide_frame() here from player.cpp to allow us to -// have one without a hardcoded player.mdl in tf_client.cpp - -/* - -===== client.cpp ======================================================== - - client/server game specific stuff - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "player.h" -#include "spectator.h" -#include "client.h" -#include "soundent.h" -#include "gamerules.h" -#include "game.h" -#include "customentity.h" -#include "weapons.h" -#include "weaponinfo.h" -#include "usercmd.h" -#include "netadr.h" -#include "pm_shared.h" - -#if defined ( GEARBOX_DLL ) -#include "gearbox_player.h" -#endif // GEARBOX_DLL - -#if !defined ( _WIN32 ) -#include -#endif - -extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; -extern DLL_GLOBAL BOOL g_fGameOver; -extern DLL_GLOBAL int g_iSkillLevel; -extern DLL_GLOBAL ULONG g_ulFrameCount; - -#if defined( GEARBOX_CTF ) -char* GetTeamName(int team); -#endif - -extern void CopyToBodyQue(entvars_t* pev); -extern int giPrecacheGrunt; -extern int gmsgSayText; - -extern cvar_t allow_spectators; - -extern int g_teamplay; - -void LinkUserMessages( void ); -void LinkUserMessages_Op4( void ); - -/* - * used by kill command and disconnect command - * ROBIN: Moved here from player.cpp, to allow multiple player models - */ -void set_suicide_frame(entvars_t* pev) -{ - if (!FStrEq(STRING(pev->model), "models/player.mdl")) - return; // allready gibbed - -// pev->frame = $deatha11; - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_TOSS; - pev->deadflag = DEAD_DEAD; - pev->nextthink = -1; -} - - -/* -=========== -ClientConnect - -called when a player connects to a server -============ -*/ -BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ - return g_pGameRules->ClientConnected( pEntity, pszName, pszAddress, szRejectReason ); - -// a client connecting during an intermission can cause problems -// if (intermission_running) -// ExitIntermission (); - -} - - -/* -=========== -ClientDisconnect - -called when a player disconnects from a server - -GLOBALS ASSUMED SET: g_fGameOver -============ -*/ -void ClientDisconnect( edict_t *pEntity ) -{ - if (g_fGameOver) - return; - - char text[256] = "" ; - if ( pEntity->v.netname ) - _snprintf( text, sizeof(text), "- %s has left the game\n", STRING(pEntity->v.netname) ); - text[ sizeof(text) - 1 ] = 0; - MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - - CSound *pSound; - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) ); - { - // since this client isn't around to think anymore, reset their sound. - if ( pSound ) - { - pSound->Reset(); - } - } - -// since the edict doesn't get deleted, fix it so it doesn't interfere. - pEntity->v.takedamage = DAMAGE_NO;// don't attract autoaim - pEntity->v.solid = SOLID_NOT;// nonsolid - UTIL_SetOrigin ( &pEntity->v, pEntity->v.origin ); - - g_pGameRules->ClientDisconnected( pEntity ); -} - - -// called by ClientKill and DeadThink -void respawn(entvars_t* pev, BOOL fCopyCorpse) -{ - if (gpGlobals->coop || gpGlobals->deathmatch) - { - if ( fCopyCorpse ) - { - // make a copy of the dead body for appearances sake - CopyToBodyQue(pev); - } - - // respawn player -#if 1 - GetClassPtr( (CGearboxPlayer *)pev)->Spawn( ); -#else - GetClassPtr( (CBasePlayer *)pev)->Spawn( ); -#endif - } - else - { // restart the entire server - SERVER_COMMAND("reload\n"); - } -} - -/* -============ -ClientKill - -Player entered the suicide command - -GLOBALS ASSUMED SET: g_ulModelIndexPlayer -============ -*/ -void ClientKill( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - -#if 1 - CGearboxPlayer *pl = (CGearboxPlayer*)CGearboxPlayer::Instance(pev); -#else - CBasePlayer *pl = (CBasePlayer*) CBasePlayer::Instance( pev ); -#endif - - if ( pl->m_fNextSuicideTime > gpGlobals->time ) - return; // prevent suiciding too ofter - - pl->m_fNextSuicideTime = gpGlobals->time + 1; // don't let them suicide for 5 seconds after suiciding - - // have the player kill themself - pev->health = 0; - pl->Killed( pev, GIB_NEVER ); - -// pev->modelindex = g_ulModelIndexPlayer; -// pev->frags -= 2; // extra penalty -// respawn( pev ); -} - -/* -=========== -ClientPutInServer - -called each time a player is spawned -============ -*/ -void ClientPutInServer( edict_t *pEntity ) -{ -#if 1 - CGearboxPlayer *pPlayer; -#else - CBasePlayer *pPlayer; -#endif - - entvars_t *pev = &pEntity->v; - -#if 1 - pPlayer = GetClassPtr((CGearboxPlayer *)pev); -#else - pPlayer = GetClassPtr((CBasePlayer *)pev); -#endif - pPlayer->SetCustomDecalFrames(-1); // Assume none; - - // Allocate a CBasePlayer for pev, and call spawn - pPlayer->Spawn() ; - - // Reset interpolation during first frame - pPlayer->pev->effects |= EF_NOINTERP; - - pPlayer->pev->iuser1 = 0; // disable any spec modes - pPlayer->pev->iuser2 = 0; -} - -#include "voice_gamemgr.h" -extern CVoiceGameMgr g_VoiceGameMgr; - - - -#if defined( _MSC_VER ) || defined( WIN32 ) -typedef wchar_t uchar16; -typedef unsigned int uchar32; -#else -typedef unsigned short uchar16; -typedef wchar_t uchar32; -#endif - -//----------------------------------------------------------------------------- -// Purpose: determine if a uchar32 represents a valid Unicode code point -//----------------------------------------------------------------------------- -bool Q_IsValidUChar32( uchar32 uVal ) -{ - // Values > 0x10FFFF are explicitly invalid; ditto for UTF-16 surrogate halves, - // values ending in FFFE or FFFF, or values in the 0x00FDD0-0x00FDEF reserved range - return ( uVal < 0x110000u ) && ( (uVal - 0x00D800u) > 0x7FFu ) && ( (uVal & 0xFFFFu) < 0xFFFEu ) && ( ( uVal - 0x00FDD0u ) > 0x1Fu ); -} - - -// Decode one character from a UTF-8 encoded string. Treats 6-byte CESU-8 sequences -// as a single character, as if they were a correctly-encoded 4-byte UTF-8 sequence. -int Q_UTF8ToUChar32( const char *pUTF8_, uchar32 &uValueOut, bool &bErrorOut ) -{ - const uint8 *pUTF8 = (const uint8 *)pUTF8_; - - int nBytes = 1; - uint32 uValue = pUTF8[0]; - uint32 uMinValue = 0; - - // 0....... single byte - if ( uValue < 0x80 ) - goto decodeFinishedNoCheck; - - // Expecting at least a two-byte sequence with 0xC0 <= first <= 0xF7 (110...... and 11110...) - if ( (uValue - 0xC0u) > 0x37u || ( pUTF8[1] & 0xC0 ) != 0x80 ) - goto decodeError; - - uValue = (uValue << 6) - (0xC0 << 6) + pUTF8[1] - 0x80; - nBytes = 2; - uMinValue = 0x80; - - // 110..... two-byte lead byte - if ( !( uValue & (0x20 << 6) ) ) - goto decodeFinished; - - // Expecting at least a three-byte sequence - if ( ( pUTF8[2] & 0xC0 ) != 0x80 ) - goto decodeError; - - uValue = (uValue << 6) - (0x20 << 12) + pUTF8[2] - 0x80; - nBytes = 3; - uMinValue = 0x800; - - // 1110.... three-byte lead byte - if ( !( uValue & (0x10 << 12) ) ) - goto decodeFinishedMaybeCESU8; - - // Expecting a four-byte sequence, longest permissible in UTF-8 - if ( ( pUTF8[3] & 0xC0 ) != 0x80 ) - goto decodeError; - - uValue = (uValue << 6) - (0x10 << 18) + pUTF8[3] - 0x80; - nBytes = 4; - uMinValue = 0x10000; - - // 11110... four-byte lead byte. fall through to finished. - -decodeFinished: - if ( uValue >= uMinValue && Q_IsValidUChar32( uValue ) ) - { -decodeFinishedNoCheck: - uValueOut = uValue; - bErrorOut = false; - return nBytes; - } -decodeError: - uValueOut = '?'; - bErrorOut = true; - return nBytes; - -decodeFinishedMaybeCESU8: - // Do we have a full UTF-16 surrogate pair that's been UTF-8 encoded afterwards? - // That is, do we have 0xD800-0xDBFF followed by 0xDC00-0xDFFF? If so, decode it all. - if ( ( uValue - 0xD800u ) < 0x400u && pUTF8[3] == 0xED && (uint8)( pUTF8[4] - 0xB0 ) < 0x10 && ( pUTF8[5] & 0xC0 ) == 0x80 ) - { - uValue = 0x10000 + ( ( uValue - 0xD800u ) << 10 ) + ( (uint8)( pUTF8[4] - 0xB0 ) << 6 ) + pUTF8[5] - 0x80; - nBytes = 6; - uMinValue = 0x10000; - } - goto decodeFinished; -} - - - -//----------------------------------------------------------------------------- -// Purpose: Returns true if UTF-8 string contains invalid sequences. -//----------------------------------------------------------------------------- -bool Q_UnicodeValidate( const char *pUTF8 ) -{ - bool bError = false; - while ( *pUTF8 ) - { - uchar32 uVal; - // Our UTF-8 decoder silently fixes up 6-byte CESU-8 (improperly re-encoded UTF-16) sequences. - // However, these are technically not valid UTF-8. So if we eat 6 bytes at once, it's an error. - int nCharSize = Q_UTF8ToUChar32( pUTF8, uVal, bError ); - if ( bError || nCharSize == 6 ) - return false; - pUTF8 += nCharSize; - } - return true; -} - -//// HOST_SAY -// String comes in as -// say blah blah blah -// or as -// blah blah blah -// -void Host_Say( edict_t *pEntity, int teamonly ) -{ -#if 1 - CGearboxPlayer *client; -#else - CBasePlayer *client; -#endif - int j; - char *p; - char text[128]; - char szTemp[256]; - const char *cpSay = "say"; - const char *cpSayTeam = "say_team"; - const char *pcmd = CMD_ARGV(0); - - // We can get a raw string now, without the "say " prepended - if ( CMD_ARGC() == 0 ) - return; - - entvars_t *pev = &pEntity->v; -#if 1 - CGearboxPlayer* player = GetClassPtr((CGearboxPlayer *)pev); -#else - CBasePlayer* player = GetClassPtr((CBasePlayer *)pev); -#endif - - //Not yet. - if ( player->m_flNextChatTime > gpGlobals->time ) - return; - - if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) ) - { - if ( CMD_ARGC() >= 2 ) - { - p = (char *)CMD_ARGS(); - } - else - { - // say with a blank message, nothing to do - return; - } - } - else // Raw text, need to prepend argv[0] - { - if ( CMD_ARGC() >= 2 ) - { - sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() ); - } - else - { - // Just a one word command, use the first word...sigh - sprintf( szTemp, "%s", ( char * )pcmd ); - } - p = szTemp; - } - -// remove quotes if present - if (*p == '"') - { - p++; - p[strlen(p)-1] = 0; - } - -// make sure the text has content - - if ( !p || !p[0] || !Q_UnicodeValidate ( p ) ) - return; // no character found, so say nothing - -// turn on color set 2 (color on, no sound) - // turn on color set 2 (color on, no sound) - if ( player->IsObserver() && ( teamonly ) ) - sprintf( text, "%c(SPEC) %s: ", 2, STRING( pEntity->v.netname ) ); - else if ( teamonly ) - sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) ); - else - sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) ); - - j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator - if ( (int)strlen(p) > j ) - p[j] = 0; - - strcat( text, p ); - strcat( text, "\n" ); - - - player->m_flNextChatTime = gpGlobals->time + CHAT_INTERVAL; - - // loop through all players - // Start with the first player. - // This may return the world in single player if the client types something between levels or during spawn - // so check it, or it will infinite loop - - client = NULL; -#if 1 - while ( ((client = (CGearboxPlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) -#else - while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) -#endif - { - if ( !client->pev ) - continue; - - if ( client->edict() == pEntity ) - continue; - - if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) - continue; - - // can the receiver hear the sender? or has he muted him? - if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, player ) ) - continue; - - if ( !player->IsObserver() && teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) - continue; - - // Spectators can only talk to other specs - if ( player->IsObserver() && teamonly ) - if ( !client->IsObserver() ) - continue; - - MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, client->pev ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - - } - - // print to the sending client - MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, &pEntity->v ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - - // echo to server console - g_engfuncs.pfnServerPrint( text ); - - char * temp; - if ( teamonly ) - temp = "say_team"; - else - temp = "say"; - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" %s \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pEntity ), "model" ), - temp, - p ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" %s \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - GETPLAYERUSERID( pEntity ), - temp, - p ); - } -} - - -/* -=========== -ClientCommand -called each time a player uses a "cmd" command -============ -*/ -extern float g_flWeaponCheat; - -// Use CMD_ARGV, CMD_ARGV, and CMD_ARGC to get pointers the character string command. -void ClientCommand( edict_t *pEntity ) -{ - const char *pcmd = CMD_ARGV(0); - const char *pstr; - - // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) - return; - - entvars_t *pev = &pEntity->v; - - if ( FStrEq(pcmd, "say" ) ) - { - Host_Say( pEntity, 0 ); - } - else if ( FStrEq(pcmd, "say_team" ) ) - { - Host_Say( pEntity, 1 ); - } - else if ( FStrEq(pcmd, "fullupdate" ) ) - { -#if 1 - GetClassPtr((CGearboxPlayer *)pev)->ForceClientDllUpdate(); -#else - GetClassPtr((CBasePlayer *)pev)->ForceClientDllUpdate(); -#endif - } - else if ( FStrEq(pcmd, "give" ) ) - { - if ( g_flWeaponCheat != 0.0) - { - int iszItem = ALLOC_STRING( CMD_ARGV(1) ); // Make a copy of the classname -#if 1 - GetClassPtr((CGearboxPlayer *)pev)->GiveNamedItem( STRING(iszItem) ); -#else - GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) ); -#endif - } - } - - else if ( FStrEq(pcmd, "drop" ) ) - { - // player is dropping an item. -#if 1 - GetClassPtr((CGearboxPlayer *)pev)->DropPlayerItem((char *)CMD_ARGV(1)); -#else - etClassPtr((CBasePlayer *)pev)->DropPlayerItem((char *)CMD_ARGV(1)); -#endif - } - else if ( FStrEq(pcmd, "fov" ) ) - { - if ( g_flWeaponCheat && CMD_ARGC() > 1) - { -#if 1 - GetClassPtr((CGearboxPlayer *)pev)->m_iFOV = atoi( CMD_ARGV(1) ); -#else - GetClassPtr((CBasePlayer *)pev)->m_iFOV = atoi( CMD_ARGV(1) ); -#endif - } - else - { -#if 1 - CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs( "\"fov\" is \"%d\"\n", (int)GetClassPtr((CGearboxPlayer *)pev)->m_iFOV ) ); -#else - CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs( "\"fov\" is \"%d\"\n", (int)GetClassPtr((CBasePlayer *)pev)->m_iFOV ) ); -#endif - } - } - else if ( FStrEq(pcmd, "use" ) ) - { -#if 1 - GetClassPtr((CGearboxPlayer *)pev)->SelectItem((char *)CMD_ARGV(1)); -#else - GetClassPtr((CBasePlayer *)pev)->SelectItem((char *)CMD_ARGV(1)); -#endif - } - else if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd)) - { -#if 1 - GetClassPtr((CGearboxPlayer *)pev)->SelectItem(pcmd); -#else - GetClassPtr((CBasePlayer *)pev)->SelectItem(pcmd); -#endif - } - else if (FStrEq(pcmd, "lastinv" )) - { -#if 1 - GetClassPtr((CGearboxPlayer *)pev)->SelectLastItem(); -#else - GetClassPtr((CBasePlayer *)pev)->SelectLastItem(); -#endif - } - else if ( FStrEq( pcmd, "spectate" ) ) // clients wants to become a spectator - { - // always allow proxies to become a spectator - if ( (pev->flags & FL_PROXY) || allow_spectators.value ) - { -#if 1 - CGearboxPlayer * pPlayer = GetClassPtr((CGearboxPlayer *)pev); -#else - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); -#endif - - edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); - pPlayer->StartObserver( pev->origin, VARS(pentSpawnSpot)->angles); - - // notify other clients of player switching to spectator mode - UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s switched to spectator mode\n", - ( pev->netname && STRING(pev->netname)[0] != 0 ) ? STRING(pev->netname) : "unconnected" ) ); - } - else - ClientPrint( pev, HUD_PRINTCONSOLE, "Spectator mode is disabled.\n" ); - - } - else if ( FStrEq( pcmd, "specmode" ) ) // new spectator mode - { -#if 1 - CGearboxPlayer * pPlayer = GetClassPtr((CGearboxPlayer *)pev); -#else - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); -#endif - - if ( pPlayer->IsObserver() ) - pPlayer->Observer_SetMode( atoi( CMD_ARGV(1) ) ); - } - else if ( FStrEq(pcmd, "closemenus" ) ) - { - // just ignore it - } - else if ( FStrEq( pcmd, "follownext" ) ) // follow next player - { -#if 1 - CGearboxPlayer * pPlayer = GetClassPtr((CGearboxPlayer *)pev); -#else - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); -#endif - - if ( pPlayer->IsObserver() ) - pPlayer->Observer_FindNextPlayer( atoi( CMD_ARGV(1) )?true:false ); - } -#if 1 - else if ( g_pGameRules->ClientCommand( GetClassPtr((CGearboxPlayer *)pev), pcmd ) ) -#else - else if ( g_pGameRules->ClientCommand( GetClassPtr((CBasePlayer *)pev), pcmd ) ) -#endif - { - // MenuSelect returns true only if the command is properly handled, so don't print a warning - } - else - { - // tell the user they entered an unknown command - char command[128]; - - // check the length of the command (prevents crash) - // max total length is 192 ...and we're adding a string below ("Unknown command: %s\n") - strncpy( command, pcmd, 127 ); - command[127] = '\0'; - - // tell the user they entered an unknown command - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", command ) ); - } -} - - -/* -======================== -ClientUserInfoChanged - -called after the player changes -userinfo - gives dll a chance to modify it before -it gets sent into the rest of the engine. -======================== -*/ -void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) -{ - // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) - return; - - // msg everyone if someone changes their name, and it isn't the first time (changing no name to current name) - if ( pEntity->v.netname && STRING(pEntity->v.netname)[0] != 0 && !FStrEq( STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" )) ) - { - char sName[256]; - char *pName = g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ); - strncpy( sName, pName, sizeof(sName) - 1 ); - sName[ sizeof(sName) - 1 ] = '\0'; - - // First parse the name and remove any %'s - for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ ) - { - // Replace it with a space - if ( *pApersand == '%' ) - *pApersand = ' '; - } - - // Set the name - g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", sName ); - - if (gpGlobals->maxClients > 1) - { - char text[256]; - sprintf( text, "* %s changed name to %s\n", STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - } - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed name to \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ), - g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" changed name to \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - GETPLAYERUSERID( pEntity ), - g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - } - } - -#if 1 - g_pGameRules->ClientUserInfoChanged( GetClassPtr((CGearboxPlayer *)&pEntity->v), infobuffer ); -#else - g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer ); -#endif -} - -static int g_serveractive = 0; - -void ServerDeactivate( void ) -{ - // It's possible that the engine will call this function more times than is necessary - // Therefore, only run it one time for each call to ServerActivate - if ( g_serveractive != 1 ) - { - return; - } - - g_serveractive = 0; - - // Peform any shutdown operations here... - // -} - -void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) -{ - int i; - CBaseEntity *pClass; - - // Every call to ServerActivate should be matched by a call to ServerDeactivate - g_serveractive = 1; - - // Clients have not been initialized yet - for ( i = 0; i < edictCount; i++ ) - { - if ( pEdictList[i].free ) - continue; - - // Clients aren't necessarily initialized until ClientPutInServer() - if ( i < clientMax || !pEdictList[i].pvPrivateData ) - continue; - - pClass = CBaseEntity::Instance( &pEdictList[i] ); - // Activate this entity if it's got a class & isn't dormant - if ( pClass && !(pClass->pev->flags & FL_DORMANT) ) - { - pClass->Activate(); - } - else - { - ALERT( at_console, "Can't instance %s\n", STRING(pEdictList[i].v.classname) ); - } - } - - // Link user messages here to make sure first client can get them... - LinkUserMessages(); - -#if 1 - // Link Op4 user messages. - LinkUserMessages_Op4(); -#endif -} - - -/* -================ -PlayerPreThink - -Called every frame before physics are run -================ -*/ -void PlayerPreThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - -#if 1 - CGearboxPlayer *pPlayer = (CGearboxPlayer *)GET_PRIVATE(pEntity); -#else - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); -#endif - - if (pPlayer) - pPlayer->PreThink( ); -} - -/* -================ -PlayerPostThink - -Called every frame after physics are run -================ -*/ -void PlayerPostThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; -#if 1 - CGearboxPlayer *pPlayer = (CGearboxPlayer *)GET_PRIVATE(pEntity); -#else - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); -#endif - - if (pPlayer) - pPlayer->PostThink( ); -} - - - -void ParmsNewLevel( void ) -{ -} - - -void ParmsChangeLevel( void ) -{ - // retrieve the pointer to the save data - SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - - if ( pSaveData ) - pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS ); -} - - -// -// GLOBALS ASSUMED SET: g_ulFrameCount -// -void StartFrame( void ) -{ - if ( g_pGameRules ) - g_pGameRules->Think(); - - if ( g_fGameOver ) - return; - - gpGlobals->teamplay = teamplay.value; - g_ulFrameCount++; -} - - -void ClientPrecache( void ) -{ - // setup precaches always needed - PRECACHE_SOUND("player/sprayer.wav"); // spray paint sound for PreAlpha - - // PRECACHE_SOUND("player/pl_jumpland2.wav"); // UNDONE: play 2x step sound - - PRECACHE_SOUND("player/pl_fallpain2.wav"); - PRECACHE_SOUND("player/pl_fallpain3.wav"); - - PRECACHE_SOUND("player/pl_step1.wav"); // walk on concrete - PRECACHE_SOUND("player/pl_step2.wav"); - PRECACHE_SOUND("player/pl_step3.wav"); - PRECACHE_SOUND("player/pl_step4.wav"); - - PRECACHE_SOUND("common/npc_step1.wav"); // NPC walk on concrete - PRECACHE_SOUND("common/npc_step2.wav"); - PRECACHE_SOUND("common/npc_step3.wav"); - PRECACHE_SOUND("common/npc_step4.wav"); - - PRECACHE_SOUND("player/pl_metal1.wav"); // walk on metal - PRECACHE_SOUND("player/pl_metal2.wav"); - PRECACHE_SOUND("player/pl_metal3.wav"); - PRECACHE_SOUND("player/pl_metal4.wav"); - - PRECACHE_SOUND("player/pl_dirt1.wav"); // walk on dirt - PRECACHE_SOUND("player/pl_dirt2.wav"); - PRECACHE_SOUND("player/pl_dirt3.wav"); - PRECACHE_SOUND("player/pl_dirt4.wav"); - - PRECACHE_SOUND("player/pl_duct1.wav"); // walk in duct - PRECACHE_SOUND("player/pl_duct2.wav"); - PRECACHE_SOUND("player/pl_duct3.wav"); - PRECACHE_SOUND("player/pl_duct4.wav"); - - PRECACHE_SOUND("player/pl_grate1.wav"); // walk on grate - PRECACHE_SOUND("player/pl_grate2.wav"); - PRECACHE_SOUND("player/pl_grate3.wav"); - PRECACHE_SOUND("player/pl_grate4.wav"); - - PRECACHE_SOUND("player/pl_slosh1.wav"); // walk in shallow water - PRECACHE_SOUND("player/pl_slosh2.wav"); - PRECACHE_SOUND("player/pl_slosh3.wav"); - PRECACHE_SOUND("player/pl_slosh4.wav"); - - PRECACHE_SOUND("player/pl_tile1.wav"); // walk on tile - PRECACHE_SOUND("player/pl_tile2.wav"); - PRECACHE_SOUND("player/pl_tile3.wav"); - PRECACHE_SOUND("player/pl_tile4.wav"); - PRECACHE_SOUND("player/pl_tile5.wav"); - - PRECACHE_SOUND("player/pl_swim1.wav"); // breathe bubbles - PRECACHE_SOUND("player/pl_swim2.wav"); - PRECACHE_SOUND("player/pl_swim3.wav"); - PRECACHE_SOUND("player/pl_swim4.wav"); - - PRECACHE_SOUND("player/pl_ladder1.wav"); // climb ladder rung - PRECACHE_SOUND("player/pl_ladder2.wav"); - PRECACHE_SOUND("player/pl_ladder3.wav"); - PRECACHE_SOUND("player/pl_ladder4.wav"); - - PRECACHE_SOUND("player/pl_wade1.wav"); // wade in water - PRECACHE_SOUND("player/pl_wade2.wav"); - PRECACHE_SOUND("player/pl_wade3.wav"); - PRECACHE_SOUND("player/pl_wade4.wav"); - - PRECACHE_SOUND("debris/wood1.wav"); // hit wood texture - PRECACHE_SOUND("debris/wood2.wav"); - PRECACHE_SOUND("debris/wood3.wav"); - - PRECACHE_SOUND("plats/train_use1.wav"); // use a train - - PRECACHE_SOUND("buttons/spark5.wav"); // hit computer texture - PRECACHE_SOUND("buttons/spark6.wav"); - PRECACHE_SOUND("debris/glass1.wav"); - PRECACHE_SOUND("debris/glass2.wav"); - PRECACHE_SOUND("debris/glass3.wav"); - - PRECACHE_SOUND( SOUND_FLASHLIGHT_ON ); - PRECACHE_SOUND( SOUND_FLASHLIGHT_OFF ); - -// player gib sounds - PRECACHE_SOUND("common/bodysplat.wav"); - -// player pain sounds - PRECACHE_SOUND("player/pl_pain2.wav"); - PRECACHE_SOUND("player/pl_pain4.wav"); - PRECACHE_SOUND("player/pl_pain5.wav"); - PRECACHE_SOUND("player/pl_pain6.wav"); - PRECACHE_SOUND("player/pl_pain7.wav"); - - PRECACHE_MODEL("models/player.mdl"); - - // hud sounds - - PRECACHE_SOUND("common/wpn_hudoff.wav"); - PRECACHE_SOUND("common/wpn_hudon.wav"); - PRECACHE_SOUND("common/wpn_moveselect.wav"); - PRECACHE_SOUND("common/wpn_select.wav"); - PRECACHE_SOUND("common/wpn_denyselect.wav"); - - - // geiger sounds - - PRECACHE_SOUND("player/geiger6.wav"); - PRECACHE_SOUND("player/geiger5.wav"); - PRECACHE_SOUND("player/geiger4.wav"); - PRECACHE_SOUND("player/geiger3.wav"); - PRECACHE_SOUND("player/geiger2.wav"); - PRECACHE_SOUND("player/geiger1.wav"); - - if (giPrecacheGrunt) - UTIL_PrecacheOther("monster_human_grunt"); - - // Teleport sounds. Used by trigger_xen_return - PRECACHE_SOUND("debris/beamstart7.wav"); - -#if defined ( GEARBOX_CTF ) - PRECACHE_MODEL("models/flag.mdl"); - PRECACHE_MODEL("models/civ_stand.mdl"); - PRECACHE_MODEL("models/mil_stand.mdl"); - - PRECACHE_MODEL("models/w_accelerator.mdl"); - PRECACHE_MODEL("models/w_backpack.mdl"); - PRECACHE_MODEL("models/w_fgrenade.mdl"); - PRECACHE_MODEL("models/w_health.mdl"); - PRECACHE_MODEL("models/w_icon.mdl"); - PRECACHE_MODEL("models/w_jumppack.mdl"); - PRECACHE_MODEL("models/w_porthev.mdl"); - - PRECACHE_SOUND("ctf/bm_flagtaken.wav"); - PRECACHE_SOUND("ctf/civ_flag_capture.wav"); - PRECACHE_SOUND("ctf/itemthrow.wav"); - PRECACHE_SOUND("ctf/marine_flag_capture.wav"); - PRECACHE_SOUND("ctf/pow_armor_charge.wav"); - PRECACHE_SOUND("ctf/pow_backpack.wav"); - PRECACHE_SOUND("ctf/pow_big_jump.wav"); - PRECACHE_SOUND("ctf/pow_health_charge.wav"); - PRECACHE_SOUND("ctf/soldier_flagtaken.wav"); -#endif -} - -/* -=============== -GetGameDescription - -Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2 -=============== -*/ -const char *GetGameDescription() -{ - if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized - return g_pGameRules->GetGameDescription(); - else - return "Half-Life"; -} - -/* -================ -Sys_Error - -Engine is going to shut down, allows setting a breakpoint in game .dll to catch that occasion -================ -*/ -void Sys_Error( const char *error_string ) -{ - // Default case, do nothing. MOD AUTHORS: Add code ( e.g., _asm { int 3 }; here to cause a breakpoint for debugging your game .dlls -} - -/* -================ -PlayerCustomization - -A new player customization has been registered on the server -UNDONE: This only sets the # of frames of the spray can logo -animation right now. -================ -*/ -void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) -{ - entvars_t *pev = &pEntity->v; -#if 1 - CGearboxPlayer *pPlayer = (CGearboxPlayer *)GET_PRIVATE(pEntity); -#else - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); -#endif - - if (!pPlayer) - { - ALERT(at_console, "PlayerCustomization: Couldn't get player!\n"); - return; - } - - if (!pCust) - { - ALERT(at_console, "PlayerCustomization: NULL customization!\n"); - return; - } - - switch (pCust->resource.type) - { - case t_decal: - pPlayer->SetCustomDecalFrames(pCust->nUserData2); // Second int is max # of frames. - break; - case t_sound: - case t_skin: - case t_model: - // Ignore for now. - break; - default: - ALERT(at_console, "PlayerCustomization: Unknown customization type!\n"); - break; - } -} - -/* -================ -SpectatorConnect - -A spectator has joined the game -================ -*/ -void SpectatorConnect( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorConnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has left the game -================ -*/ -void SpectatorDisconnect( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorDisconnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has sent a usercmd -================ -*/ -void SpectatorThink( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorThink( ); -} - -//////////////////////////////////////////////////////// -// PAS and PVS routines for client messaging -// - -/* -================ -SetupVisibility - -A client can have a separate "view entity" indicating that his/her view should depend on the origin of that -view entity. If that's the case, then pViewEntity will be non-NULL and will be used. Otherwise, the current -entity's origin is used. Either is offset by the view_ofs to get the eye position. - -From the eye position, we set up the PAS and PVS to use for filtering network messages to the client. At this point, we could - override the actual PAS or PVS values, or use a different origin. - -NOTE: Do not cache the values of pas and pvs, as they depend on reusable memory in the engine, they are only good for this one frame -================ -*/ -void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ) -{ - Vector org; - edict_t *pView = pClient; - - // Find the client's PVS - if ( pViewEntity ) - { - pView = pViewEntity; - } - - if ( pClient->v.flags & FL_PROXY ) - { - *pvs = NULL; // the spectator proxy sees - *pas = NULL; // and hears everything - return; - } - - org = pView->v.origin + pView->v.view_ofs; - if ( pView->v.flags & FL_DUCKING ) - { - org = org + ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); - } - - *pvs = ENGINE_SET_PVS ( (float *)&org ); - *pas = ENGINE_SET_PAS ( (float *)&org ); -} - -#include "entity_state.h" - -/* -AddToFullPack - -Return 1 if the entity state has been filled in for the ent and the entity will be propagated to the client, 0 otherwise - -state is the server maintained copy of the state info that is transmitted to the client -a MOD could alter values copied into state to send the "host" a different look for a particular entity update, etc. -e and ent are the entity that is being added to the update, if 1 is returned -host is the player's edict of the player whom we are sending the update to -player is 1 if the ent/e is a player and 0 otherwise -pSet is either the PAS or PVS that we previous set up. We can use it to ask the engine to filter the entity against the PAS or PVS. -we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to. Caching the value is valid in that case, but still only for the current frame -*/ -int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) -{ - int i; - - // don't send if flagged for NODRAW and it's not the host getting the message - if ( ( ent->v.effects & EF_NODRAW ) && - ( ent != host ) ) - return 0; - - // Ignore ents without valid / visible models - if ( !ent->v.modelindex || !STRING( ent->v.model ) ) - return 0; - - // Don't send spectators to other players - if ( ( ent->v.flags & FL_SPECTATOR ) && ( ent != host ) ) - { - return 0; - } - - // Ignore if not the host and not touching a PVS/PAS leaf - // If pSet is NULL, then the test will always succeed and the entity will be added to the update - if ( ent != host ) - { - if ( !ENGINE_CHECK_VISIBILITY( (const struct edict_s *)ent, pSet ) ) - { - return 0; - } - } - - - // Don't send entity to local client if the client says it's predicting the entity itself. - if ( ent->v.flags & FL_SKIPLOCALHOST ) - { - if ( ( hostflags & 1 ) && ( ent->v.owner == host ) ) - return 0; - } - - if ( host->v.groupinfo ) - { - UTIL_SetGroupTrace( host->v.groupinfo, GROUP_OP_AND ); - - // Should always be set, of course - if ( ent->v.groupinfo ) - { - if ( g_groupop == GROUP_OP_AND ) - { - if ( !(ent->v.groupinfo & host->v.groupinfo ) ) - return 0; - } - else if ( g_groupop == GROUP_OP_NAND ) - { - if ( ent->v.groupinfo & host->v.groupinfo ) - return 0; - } - } - - UTIL_UnsetGroupTrace(); - } - - memset( state, 0, sizeof( *state ) ); - - // Assign index so we can track this entity from frame to frame and - // delta from it. - state->number = e; - state->entityType = ENTITY_NORMAL; - - // Flag custom entities. - if ( ent->v.flags & FL_CUSTOMENTITY ) - { - state->entityType = ENTITY_BEAM; - } - - // - // Copy state data - // - - // Round animtime to nearest millisecond - state->animtime = (int)(1000.0 * ent->v.animtime ) / 1000.0; - - memcpy( state->origin, ent->v.origin, 3 * sizeof( float ) ); - memcpy( state->angles, ent->v.angles, 3 * sizeof( float ) ); - memcpy( state->mins, ent->v.mins, 3 * sizeof( float ) ); - memcpy( state->maxs, ent->v.maxs, 3 * sizeof( float ) ); - - memcpy( state->startpos, ent->v.startpos, 3 * sizeof( float ) ); - memcpy( state->endpos, ent->v.endpos, 3 * sizeof( float ) ); - - state->impacttime = ent->v.impacttime; - state->starttime = ent->v.starttime; - - state->modelindex = ent->v.modelindex; - - state->frame = ent->v.frame; - - state->skin = ent->v.skin; - state->effects = ent->v.effects; - - // This non-player entity is being moved by the game .dll and not the physics simulation system - // make sure that we interpolate it's position on the client if it moves - if ( !player && - ent->v.animtime && - ent->v.velocity[ 0 ] == 0 && - ent->v.velocity[ 1 ] == 0 && - ent->v.velocity[ 2 ] == 0 ) - { - state->eflags |= EFLAG_SLERP; - } - - state->scale = ent->v.scale; - state->solid = ent->v.solid; - state->colormap = ent->v.colormap; - - state->movetype = ent->v.movetype; - state->sequence = ent->v.sequence; - state->framerate = ent->v.framerate; - state->body = ent->v.body; - - for (i = 0; i < 4; i++) - { - state->controller[i] = ent->v.controller[i]; - } - - for (i = 0; i < 2; i++) - { - state->blending[i] = ent->v.blending[i]; - } - - state->rendermode = ent->v.rendermode; - state->renderamt = ent->v.renderamt; - state->renderfx = ent->v.renderfx; - state->rendercolor.r = ent->v.rendercolor.x; - state->rendercolor.g = ent->v.rendercolor.y; - state->rendercolor.b = ent->v.rendercolor.z; - - state->aiment = 0; - if ( ent->v.aiment ) - { - state->aiment = ENTINDEX( ent->v.aiment ); - } - - state->owner = 0; - if ( ent->v.owner ) - { - int owner = ENTINDEX( ent->v.owner ); - - // Only care if owned by a player - if ( owner >= 1 && owner <= gpGlobals->maxClients ) - { - state->owner = owner; - } - } - - // HACK: Somewhat... - // Class is overridden for non-players to signify a breakable glass object ( sort of a class? ) - if ( !player ) - { - state->playerclass = ent->v.playerclass; - } - - // Special stuff for players only - if ( player ) - { - memcpy( state->basevelocity, ent->v.basevelocity, 3 * sizeof( float ) ); - - state->weaponmodel = MODEL_INDEX( STRING( ent->v.weaponmodel ) ); - state->gaitsequence = ent->v.gaitsequence; - state->spectator = ent->v.flags & FL_SPECTATOR; - state->friction = ent->v.friction; - - state->gravity = ent->v.gravity; -// state->team = ent->v.team; -// - state->usehull = ( ent->v.flags & FL_DUCKING ) ? 1 : 0; - state->health = ent->v.health; - } - - return 1; -} - -// defaults for clientinfo messages -#define DEFAULT_VIEWHEIGHT 28 - -/* -=================== -CreateBaseline - -Creates baselines used for network encoding, especially for player data since players are not spawned until connect time. -=================== -*/ -void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ) -{ - baseline->origin = entity->v.origin; - baseline->angles = entity->v.angles; - baseline->frame = entity->v.frame; - baseline->skin = (short)entity->v.skin; - - // render information - baseline->rendermode = (byte)entity->v.rendermode; - baseline->renderamt = (byte)entity->v.renderamt; - baseline->rendercolor.r = (byte)entity->v.rendercolor.x; - baseline->rendercolor.g = (byte)entity->v.rendercolor.y; - baseline->rendercolor.b = (byte)entity->v.rendercolor.z; - baseline->renderfx = (byte)entity->v.renderfx; - - if ( player ) - { - baseline->mins = player_mins; - baseline->maxs = player_maxs; - - baseline->colormap = eindex; - baseline->modelindex = playermodelindex; - baseline->friction = 1.0; - baseline->movetype = MOVETYPE_WALK; - - baseline->scale = entity->v.scale; - baseline->solid = SOLID_SLIDEBOX; - baseline->framerate = 1.0; - baseline->gravity = 1.0; - - } - else - { - baseline->mins = entity->v.mins; - baseline->maxs = entity->v.maxs; - - baseline->colormap = 0; - baseline->modelindex = entity->v.modelindex;//SV_ModelIndex(pr_strings + entity->v.model); - baseline->movetype = entity->v.movetype; - - baseline->scale = entity->v.scale; - baseline->solid = entity->v.solid; - baseline->framerate = entity->v.framerate; - baseline->gravity = entity->v.gravity; - } -} - -typedef struct -{ - char name[32]; - int field; -} entity_field_alias_t; - -#define FIELD_ORIGIN0 0 -#define FIELD_ORIGIN1 1 -#define FIELD_ORIGIN2 2 -#define FIELD_ANGLES0 3 -#define FIELD_ANGLES1 4 -#define FIELD_ANGLES2 5 - -static entity_field_alias_t entity_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, - { "angles[0]", 0 }, - { "angles[1]", 0 }, - { "angles[2]", 0 }, -}; - -void Entity_FieldInit( struct delta_s *pFields ) -{ - entity_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN0 ].name ); - entity_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN1 ].name ); - entity_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN2 ].name ); - entity_field_alias[ FIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES0 ].name ); - entity_field_alias[ FIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES1 ].name ); - entity_field_alias[ FIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES2 ].name ); -} - -/* -================== -Entity_Encode - -Callback for sending entity_state_t info over network. -FIXME: Move to script -================== -*/ -void Entity_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int localplayer = 0; - static int initialized = 0; - - if ( !initialized ) - { - Entity_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - // Never send origin to local player, it's sent with more resolution in clientdata_t structure - localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); - if ( localplayer ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->impacttime != 0 ) && ( t->starttime != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } -} - -static entity_field_alias_t player_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, -}; - -void Player_FieldInit( struct delta_s *pFields ) -{ - player_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN0 ].name ); - player_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN1 ].name ); - player_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN2 ].name ); -} - -/* -================== -Player_Encode - -Callback for sending entity_state_t for players info over network. -================== -*/ -void Player_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int localplayer = 0; - static int initialized = 0; - - if ( !initialized ) - { - Player_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - // Never send origin to local player, it's sent with more resolution in clientdata_t structure - localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); - if ( localplayer ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } -} - -#define CUSTOMFIELD_ORIGIN0 0 -#define CUSTOMFIELD_ORIGIN1 1 -#define CUSTOMFIELD_ORIGIN2 2 -#define CUSTOMFIELD_ANGLES0 3 -#define CUSTOMFIELD_ANGLES1 4 -#define CUSTOMFIELD_ANGLES2 5 -#define CUSTOMFIELD_SKIN 6 -#define CUSTOMFIELD_SEQUENCE 7 -#define CUSTOMFIELD_ANIMTIME 8 - -entity_field_alias_t custom_entity_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, - { "angles[0]", 0 }, - { "angles[1]", 0 }, - { "angles[2]", 0 }, - { "skin", 0 }, - { "sequence", 0 }, - { "animtime", 0 }, -}; - -void Custom_Entity_FieldInit( struct delta_s *pFields ) -{ - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].name ); - custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].name ); -} - -/* -================== -Custom_Encode - -Callback for sending entity_state_t info ( for custom entities ) over network. -FIXME: Move to script -================== -*/ -void Custom_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int beamType; - static int initialized = 0; - - if ( !initialized ) - { - Custom_Entity_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - beamType = t->rendermode & 0x0f; - - if ( beamType != BEAM_POINTS && beamType != BEAM_ENTPOINT ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field ); - } - - if ( beamType != BEAM_POINTS ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field ); - } - - if ( beamType != BEAM_ENTS && beamType != BEAM_ENTPOINT ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field ); - } - - // animtime is compared by rounding first - // see if we really shouldn't actually send it - if ( (int)f->animtime == (int)t->animtime ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field ); - } -} - -/* -================= -RegisterEncoders - -Allows game .dll to override network encoding of certain types of entities and tweak values, etc. -================= -*/ -void RegisterEncoders( void ) -{ - DELTA_ADDENCODER( "Entity_Encode", Entity_Encode ); - DELTA_ADDENCODER( "Custom_Encode", Custom_Encode ); - DELTA_ADDENCODER( "Player_Encode", Player_Encode ); -} - -int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) -{ -#if CLIENT_WEAPONS - int i; - weapon_data_t *item; - entvars_t *pev = &player->v; -#if 1 - CGearboxPlayer *pl = dynamic_cast< CGearboxPlayer *>(CGearboxPlayer::Instance(pev)); -#else - CBasePlayer *pl = dynamic_cast< CBasePlayer *>( CBasePlayer::Instance( pev ) ); -#endif - CBasePlayerWeapon *gun; - - ItemInfo II; - - memset( info, 0, 32 * sizeof( weapon_data_t ) ); - - if ( !pl ) - return 1; - - // go through all of the weapons and make a list of the ones to pack - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( pl->m_rgpPlayerItems[ i ] ) - { - // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = pl->m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - gun = dynamic_cast( pPlayerItem->GetWeaponPtr() ); - if ( gun && gun->UseDecrement() ) - { - // Get The ID. - memset( &II, 0, sizeof( II ) ); - gun->GetItemInfo( &II ); - - if ( II.iId >= 0 && II.iId < 32 ) - { - item = &info[ II.iId ]; - - item->m_iId = II.iId; - item->m_iClip = gun->m_iClip; - - item->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle, -0.001 ); - item->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack, -0.001 ); - item->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack, -0.001 ); - item->m_fInReload = gun->m_fInReload; - item->m_fInSpecialReload = gun->m_fInSpecialReload; - item->fuser1 = max( gun->pev->fuser1, -0.001 ); - item->fuser2 = gun->m_flStartThrow; - item->fuser3 = gun->m_flReleaseThrow; - item->iuser1 = gun->m_chargeReady; - item->iuser2 = gun->m_fInAttack; - item->iuser3 = gun->m_fireState; - - -// item->m_flPumpTime = max( gun->m_flPumpTime, -0.001 ); - } - } - pPlayerItem = pPlayerItem->m_pNext; - } - } - } -#else - memset( info, 0, 32 * sizeof( weapon_data_t ) ); -#endif - return 1; -} - -/* -================= -UpdateClientData - -Data sent to current client only -engine sets cd to 0 before calling. -================= -*/ -void UpdateClientData ( const edict_t *ent, int sendweapons, struct clientdata_s *cd ) -{ - if ( !ent || !ent->pvPrivateData ) - return; - entvars_t * pev = (entvars_t *)&ent->v; -#if 1 - CGearboxPlayer * pl = dynamic_cast< CGearboxPlayer *>(CGearboxPlayer::Instance(pev)); -#else - CBasePlayer * pl = dynamic_cast< CBasePlayer *>(CBasePlayer::Instance( pev )); -#endif - entvars_t * pevOrg = NULL; - - // if user is spectating different player in First person, override some vars - if ( pl && pl->pev->iuser1 == OBS_IN_EYE ) - { - if ( pl->m_hObserverTarget ) - { - pevOrg = pev; - pev = pl->m_hObserverTarget->pev; -#if 1 - pl = dynamic_cast< CGearboxPlayer *>(CGearboxPlayer::Instance(pev)); -#else - pl = dynamic_cast< CBasePlayer *>(CBasePlayer::Instance( pev ) ); -#endif - } - } - - cd->flags = pev->flags; - cd->health = pev->health; - - cd->viewmodel = MODEL_INDEX( STRING( pev->viewmodel ) ); - - cd->waterlevel = pev->waterlevel; - cd->watertype = pev->watertype; - cd->weapons = pev->weapons; - - // Vectors - cd->origin = pev->origin; - cd->velocity = pev->velocity; - cd->view_ofs = pev->view_ofs; - cd->punchangle = pev->punchangle; - - cd->bInDuck = pev->bInDuck; - cd->flTimeStepSound = pev->flTimeStepSound; - cd->flDuckTime = pev->flDuckTime; - cd->flSwimTime = pev->flSwimTime; - cd->waterjumptime = pev->teleport_time; - - strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); - - cd->maxspeed = pev->maxspeed; - cd->fov = pev->fov; - cd->weaponanim = pev->weaponanim; - - cd->pushmsec = pev->pushmsec; - - //Spectator mode - if ( pevOrg != NULL ) - { - // don't use spec vars from chased player - cd->iuser1 = pevOrg->iuser1; - cd->iuser2 = pevOrg->iuser2; - } - else - { - cd->iuser1 = pev->iuser1; - cd->iuser2 = pev->iuser2; - } - - - -#if CLIENT_WEAPONS - if ( sendweapons ) - { - if ( pl ) - { - cd->m_flNextAttack = pl->m_flNextAttack; - cd->fuser2 = pl->m_flNextAmmoBurn; - cd->fuser3 = pl->m_flAmmoStartCharge; - cd->vuser1.x = pl->ammo_9mm; - cd->vuser1.y = pl->ammo_357; - cd->vuser1.z = pl->ammo_argrens; - cd->ammo_nails = pl->ammo_bolts; - cd->ammo_shells = pl->ammo_buckshot; - cd->ammo_rockets = pl->ammo_rockets; - cd->ammo_cells = pl->ammo_uranium; - cd->vuser2.x = pl->ammo_hornets; - - if ( pl->m_pActiveItem ) - { - CBasePlayerWeapon *gun; - gun = (CBasePlayerWeapon *)pl->m_pActiveItem->GetWeaponPtr(); - if ( gun && gun->UseDecrement() ) - { - ItemInfo II; - memset( &II, 0, sizeof( II ) ); - gun->GetItemInfo( &II ); - - cd->m_iId = II.iId; - - cd->vuser3.z = gun->m_iSecondaryAmmoType; - cd->vuser4.x = gun->m_iPrimaryAmmoType; - cd->vuser4.y = pl->m_rgAmmo[gun->m_iPrimaryAmmoType]; - cd->vuser4.z = pl->m_rgAmmo[gun->m_iSecondaryAmmoType]; - - if ( pl->m_pActiveItem->m_iId == WEAPON_RPG ) - { - cd->vuser2.y = ( ( CRpg * )pl->m_pActiveItem)->m_fSpotActive; - cd->vuser2.z = ( ( CRpg * )pl->m_pActiveItem)->m_cActiveRockets; - } -#if defined ( GEARBOX_DLL ) || defined ( GEARBOX_CLIENT_DLL ) - else if (pl->m_pActiveItem->m_iId == WEAPON_M249) - { - cd->vuser2.y = pl->ammo_556; - } - else if (pl->m_pActiveItem->m_iId == WEAPON_SHOCKRIFLE) - { - cd->vuser2.y = pl->ammo_shocks; - } - else if (pl->m_pActiveItem->m_iId == WEAPON_SNIPERRIFLE) - { - cd->vuser2.y = pl->ammo_762; - } - else if (pl->m_pActiveItem->m_iId == WEAPON_SPORELAUNCHER) - { - cd->vuser2.y = pl->ammo_spores; - } -#endif - } - } - } - } -#endif -} - -/* -================= -CmdStart - -We're about to run this usercmd for the specified player. We can set up groupinfo and masking here, etc. -This is the time to examine the usercmd for anything extra. This call happens even if think does not. -================= -*/ -void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ) -{ - entvars_t *pev = (entvars_t *)&player->v; -#if 1 - CGearboxPlayer *pl = dynamic_cast< CGearboxPlayer *>(CGearboxPlayer::Instance(pev)); -#else - CBasePlayer *pl = dynamic_cast< CBasePlayer *>( CBasePlayer::Instance( pev ) ); -#endif - - if( !pl ) - return; - - if ( pl->pev->groupinfo != 0 ) - { - UTIL_SetGroupTrace( pl->pev->groupinfo, GROUP_OP_AND ); - } - - pl->random_seed = random_seed; -} - -/* -================= -CmdEnd - -Each cmdstart is exactly matched with a cmd end, clean up any group trace flags, etc. here -================= -*/ -void CmdEnd ( const edict_t *player ) -{ - entvars_t *pev = (entvars_t *)&player->v; -#if 1 - CGearboxPlayer *pl = dynamic_cast< CGearboxPlayer *>(CGearboxPlayer::Instance(pev)); -#else - CBasePlayer *pl = dynamic_cast< CBasePlayer *>( CBasePlayer::Instance( pev ) ); -#endif - - if( !pl ) - return; - if ( pl->pev->groupinfo != 0 ) - { - UTIL_UnsetGroupTrace(); - } -} - -/* -================================ -ConnectionlessPacket - - Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max - size of the response_buffer, so you must zero it out if you choose not to respond. -================================ -*/ -int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) -{ - // Parse stuff from args - int max_buffer_size = *response_buffer_size; - - // Zero it out since we aren't going to respond. - // If we wanted to response, we'd write data into response_buffer - *response_buffer_size = 0; - - // Since we don't listen for anything here, just respond that it's a bogus message - // If we didn't reject the message, we'd return 1 for success instead. - return 0; -} - -/* -================================ -GetHullBounds - - Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. -================================ -*/ -int GetHullBounds( int hullnumber, float *mins, float *maxs ) -{ - int iret = 0; - - switch ( hullnumber ) - { - case 0: // Normal player - mins = VEC_HULL_MIN; - maxs = VEC_HULL_MAX; - iret = 1; - break; - case 1: // Crouched player - mins = VEC_DUCK_HULL_MIN; - maxs = VEC_DUCK_HULL_MAX; - iret = 1; - break; - case 2: // Point based hull - mins = Vector( 0, 0, 0 ); - maxs = Vector( 0, 0, 0 ); - iret = 1; - break; - } - - return iret; -} - -/* -================================ -CreateInstancedBaselines - -Create pseudo-baselines for items that aren't placed in the map at spawn time, but which are likely -to be created during play ( e.g., grenades, ammo packs, projectiles, corpses, etc. ) -================================ -*/ -void CreateInstancedBaselines ( void ) -{ - int iret = 0; - entity_state_t state; - - memset( &state, 0, sizeof( state ) ); - - // Create any additional baselines here for things like grendates, etc. - // iret = ENGINE_INSTANCE_BASELINE( pc->pev->classname, &state ); - - // Destroy objects. - //UTIL_Remove( pc ); -} - -/* -================================ -InconsistentFile - -One of the ENGINE_FORCE_UNMODIFIED files failed the consistency check for the specified player - Return 0 to allow the client to continue, 1 to force immediate disconnection ( with an optional disconnect message of up to 256 characters ) -================================ -*/ -int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) -{ - // Server doesn't care? - if ( CVAR_GET_FLOAT( "mp_consistency" ) != 1 ) - return 0; - - // Default behavior is to kick the player - sprintf( disconnect_message, "Server is enforcing file consistency for %s\n", filename ); - - // Kick now with specified disconnect message. - return 1; -} - -/* -================================ -AllowLagCompensation - - The game .dll should return 1 if lag compensation should be allowed ( could also just set - the sv_unlag cvar. - Most games right now should return 0, until client-side weapon prediction code is written - and tested for them ( note you can predict weapons, but not do lag compensation, too, - if you want. -================================ -*/ -int AllowLagCompensation( void ) -{ - return 1; -} diff --git a/dlls/gearbox/gearbox_explode.h b/dlls/gearbox/gearbox_explode.h deleted file mode 100644 index c3332320..00000000 --- a/dlls/gearbox/gearbox_explode.h +++ /dev/null @@ -1,25 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef GEARBOX_EXPLODE_H -#define GEARBOX_EXPLODE_H - -extern DLL_GLOBAL short g_sModelIndexSpore1; -extern DLL_GLOBAL short g_sModelIndexSpore2; -extern DLL_GLOBAL short g_sModelIndexSpore3; - -extern DLL_GLOBAL short g_sModelIndexBigSpit; -extern DLL_GLOBAL short g_sModelIndexTinySpit; - -#endif // GEARBOX_EXPLODE_H \ No newline at end of file diff --git a/dlls/gearbox/gearbox_monsters.h b/dlls/gearbox/gearbox_monsters.h deleted file mode 100644 index b958a8b9..00000000 --- a/dlls/gearbox/gearbox_monsters.h +++ /dev/null @@ -1,21 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef GEARBOX_MONSTERS_H -#define GEARBOX_MONSTERS_H - -#define EF_GLOWSHELL 2048 - -#endif // GEARBOX_MONSTERS_H \ No newline at end of file diff --git a/dlls/gearbox/gearbox_player.h b/dlls/gearbox/gearbox_player.h deleted file mode 100644 index 512488c5..00000000 --- a/dlls/gearbox/gearbox_player.h +++ /dev/null @@ -1,79 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef GEARBOX_PLAYER_H -#define GEARBOX_PLAYER_H - -enum Player_Menu { - Team_Menu, - Team_Menu_IG, -}; - -#define PFLAG_ONROPE ( 1 << 6 ) - -class CGearboxPlayer : public CBasePlayer -{ -public: - virtual int Save(CSave &save); - virtual int Restore(CRestore &restore); - - BOOL FlashlightIsOn(void); - void FlashlightTurnOn(void); - void FlashlightTurnOff(void); - - static TYPEDESCRIPTION m_playerSaveData[]; - - virtual void Spawn(void); - -private: - BOOL m_fInXen; - BOOL m_fIsFrozen; - -public: - int m_bHasFlag; - void ShowMenu(int bitsValidSlots, int nDisplayTime, BOOL fNeedMore, char *pszText); - int m_iMenu; - - float m_flNextTeamChange; - - CBasePlayer *pFlagCarrierKiller; - CBasePlayer *pFlagReturner; - CBasePlayer *pCarrierHurter; - - float m_flCarrierHurtTime; - float m_flCarrierPickupTime; - float m_flFlagCarrierKillTime; - float m_flFlagReturnTime; - float m_flFlagStatusTime; - - float m_flRegenTime; - - int m_iRuneStatus; - - void W_FireHook(void); - void Throw_Grapple(void); - - bool m_bHook_Out; - bool m_bOn_Hook; - CBaseEntity *m_ppHook; - - void Service_Grapple(void); -private: - - friend class CDisplacer; - friend class CTriggerXenReturn; - friend class CPlayerFreeze; -}; - -#endif // GEARBOX_PLAYER_H diff --git a/wscript b/wscript index 02efd884..4e5503ed 100644 --- a/wscript +++ b/wscript @@ -211,7 +211,7 @@ def configure(conf): conf.msg(msg='-> processing mod options', result='...', color='BLUE') regex = re.compile('^([A-Za-z0-9_]+)=([A-Za-z0-9_]+)\ \#\ (.*)$') - with open('mod_options.txt') as fd: + with open(str(conf.path.make_node('mod_options.txt'))) as fd: lines = fd.readlines() for line in lines: m = regex.match(line.strip()) @@ -230,6 +230,10 @@ def configure(conf): if conf.env.HLDEMO_BUILD and conf.env.OEM_BUILD: conf.fatal('Don\'t mix Demo and OEM builds!') + # force to use server library name + if conf.env.DEST_OS == 'android': + conf.env.SERVER_LIBRARY_NAME = 'server' # can't be any other name, until specified + # strip lib from pattern if conf.env.DEST_OS not in ['android']: if conf.env.cxxshlib_PATTERN.startswith('lib'):