diff options
| author | Vladimir Druzenko <vvd@FreeBSD.org> | 2025-02-22 21:48:35 +0000 |
|---|---|---|
| committer | Vladimir Druzenko <vvd@FreeBSD.org> | 2025-02-22 21:48:35 +0000 |
| commit | 5578dbccb5f6a2d1bda001b4e8a78f626c491918 (patch) | |
| tree | 8489d031e491e19c5262d094cd3cab2fda0408bf | |
| parent | 7927033436e985b385fe58a83c5341954a505b50 (diff) | |
games/qtv: New port: QuakeWorld match broadcasting tool
The maximum number of players and spectators in QuakeWorld is 32. QTV
allows hundreds and even thousands of spectators to watch the game at
the same time. Also, a delay of about 10 seconds has been added so that
spectators cannot prompt players with information about opponents during
the game via voice chats. In such a dynamic game as QuakeWorld, a lot
can change in a few seconds and the information will be out of date.
| -rw-r--r-- | games/Makefile | 1 | ||||
| -rw-r--r-- | games/qtv/Makefile | 49 | ||||
| -rw-r--r-- | games/qtv/distinfo | 3 | ||||
| -rw-r--r-- | games/qtv/files/patch-src_fs.c | 20 | ||||
| -rw-r--r-- | games/qtv/files/patch-src_main.c | 15 | ||||
| -rw-r--r-- | games/qtv/files/patch-src_net__utils.c | 18 | ||||
| -rwxr-xr-x | games/qtv/files/qtv.in | 106 | ||||
| -rw-r--r-- | games/qtv/pkg-descr | 8 | ||||
| -rw-r--r-- | games/qtv/pkg-plist | 102 |
9 files changed, 322 insertions, 0 deletions
diff --git a/games/Makefile b/games/Makefile index a4086e1704cd..a18ec83e29c7 100644 --- a/games/Makefile +++ b/games/Makefile @@ -819,6 +819,7 @@ SUBDIR += qonk SUBDIR += qqwing SUBDIR += qstat + SUBDIR += qtv SUBDIR += quackle SUBDIR += quadra SUBDIR += quadrapassel diff --git a/games/qtv/Makefile b/games/qtv/Makefile new file mode 100644 index 000000000000..b6a6739600a6 --- /dev/null +++ b/games/qtv/Makefile @@ -0,0 +1,49 @@ +PORTNAME= qtv +DISTVERSION= 1.15 +CATEGORIES= games + +MAINTAINER= vvd@FreeBSD.org +COMMENT= QuakeWorld match broadcasting tool +WWW= https://github.com/QW-Group/qtv/ + +LICENSE= GPLv2 +LICENSE_FILE= ${WRKSRC}/LICENSE.md + +USES= cmake + +USE_GITHUB= yes +GH_ACCOUNT= QW-Group +USE_RC_SUBR= ${PORTNAME} + +EXTRACT_AFTER_ARGS= --exclude .git* \ + --exclude */.git* \ + --exclude build_cmake.sh \ + --exclude resources/example-configs/"PLACE YOUR QTV.BIN HERE" \ + --exclude resources/metaqtv* \ + --exclude tools* + +QWDIR= ${PREFIX}/quake +SUB_LIST= QWDIR=${QWDIR} QWUSER=${USERS} +USERS= qw +GROUPS= qw +PLIST_SUB= QWGROUP=${GROUPS} +PORTDOCS= README.md + +OPTIONS_DEFINE= DOCS + +do-install: + ${INSTALL_PROGRAM} ${BUILD_WRKSRC}/${PORTNAME} ${STAGEDIR}${PREFIX}/bin + cd ${WRKSRC}/resources/example-configs && \ + ${COPYTREE_SHARE} ${PORTNAME} ${STAGEDIR}${QWDIR} + ${MV} ${STAGEDIR}${QWDIR}/${PORTNAME}/listip.cfg \ + ${STAGEDIR}${QWDIR}/${PORTNAME}/listip.cfg.sample + ${INSTALL_DATA} ${WRKSRC}/resources/example-configs/${PORTNAME}.cfg \ + ${STAGEDIR}${QWDIR}/${PORTNAME}/${PORTNAME}.cfg.sample + +do-install-DOCS-on: + ${MKDIR} ${STAGEDIR}${DOCSDIR} + ${INSTALL_DATA} ${PORTDOCS:S,^,${WRKSRC}/,} ${STAGEDIR}${DOCSDIR} + ${INSTALL_DATA} ${WRKSRC}/resources/example-configs/README.1ST \ + ${STAGEDIR}${DOCSDIR} + +.include <bsd.port.mk> diff --git a/games/qtv/distinfo b/games/qtv/distinfo new file mode 100644 index 000000000000..e44a8b3b80f7 --- /dev/null +++ b/games/qtv/distinfo @@ -0,0 +1,3 @@ +TIMESTAMP = 1739923712 +SHA256 (QW-Group-qtv-1.15_GH0.tar.gz) = ab9e699bb0894dd8274c8c7c56d7bba44e75b2a123baf17212aa2f60aef6111c +SIZE (QW-Group-qtv-1.15_GH0.tar.gz) = 1000884 diff --git a/games/qtv/files/patch-src_fs.c b/games/qtv/files/patch-src_fs.c new file mode 100644 index 000000000000..53efa85406cb --- /dev/null +++ b/games/qtv/files/patch-src_fs.c @@ -0,0 +1,20 @@ +--- src/fs.c.orig 2025-02-16 14:10:58 UTC ++++ src/fs.c +@@ -119,6 +119,7 @@ void FS_StripPathAndExtension(char *filepath) + size_t lastslash = (size_t) -1; + size_t lastdot = (size_t) -1; + size_t i = 0; ++ char temp_filepath[MAX_QPATH]; + + for ( ; filepath[i]; i++) + { +@@ -131,7 +132,8 @@ void FS_StripPathAndExtension(char *filepath) + if (lastdot == (size_t) -1 || lastdot < lastslash) + lastdot = i; + +- strlcpy(filepath, filepath + lastslash + 1, lastdot - lastslash); ++ strlcpy(temp_filepath, filepath + lastslash + 1, lastdot - lastslash); ++ strlcpy(filepath, temp_filepath, sizeof(temp_filepath)); + } + + // return file extension with dot, or empty string if dot not found at all diff --git a/games/qtv/files/patch-src_main.c b/games/qtv/files/patch-src_main.c new file mode 100644 index 000000000000..42aa78f7e007 --- /dev/null +++ b/games/qtv/files/patch-src_main.c @@ -0,0 +1,15 @@ +--- src/main.c.orig 2025-02-16 14:10:58 UTC ++++ src/main.c +@@ -274,6 +274,12 @@ int main(int argc, char **argv) + } + #endif // _WIN32 + ++ // Disable buffering for stdout and stderr to avoid issues when output ++ // is redirected to a file or pipe instead of being displayed in a ++ // terminal. ++ setbuf(stdout, NULL); ++ setbuf(stderr, NULL); ++ + memset(&g_cluster, 0, sizeof(g_cluster)); + + g_cluster.tcpsocket = INVALID_SOCKET; diff --git a/games/qtv/files/patch-src_net__utils.c b/games/qtv/files/patch-src_net__utils.c new file mode 100644 index 000000000000..f87e702b97db --- /dev/null +++ b/games/qtv/files/patch-src_net__utils.c @@ -0,0 +1,18 @@ +--- src/net_utils.c.orig 2025-02-16 14:10:58 UTC ++++ src/net_utils.c +@@ -60,11 +60,13 @@ char *Net_BaseAdrToString (struct sockaddr_in *a, char + // Windows have inet_ntop only starting from Vista. Sigh. + #ifdef _WIN32 + const char *result = inet_ntoa(a->sin_addr); ++ strlcpy(buf, result ? result : "", bufsize); + #else + const char *result = inet_ntop(a->sin_family, &a->sin_addr, buf, bufsize); ++ if (!result) { ++ strlcpy(buf, "", bufsize); ++ } + #endif +- +- strlcpy(buf, result ? result : "", bufsize); + + return buf; + } diff --git a/games/qtv/files/qtv.in b/games/qtv/files/qtv.in new file mode 100755 index 000000000000..7be83aed5b0f --- /dev/null +++ b/games/qtv/files/qtv.in @@ -0,0 +1,106 @@ +#!/bin/sh + +# PROVIDE: qtv +# REQUIRE: LOGIN +# KEYWORD: shutdown +# +# Add the following lines to /etc/rc.conf or /etc/rc.conf.local to +# enable qtv: +# qtv_(instance_)?enable (bool): Set to "NO" by default. +# Set it to "YES" to enable qtv. +# qtv_(instance_)?args (str): Custom additional arguments to be passed +# to qtv (default empty). +# qtv_(instance_)?user (str): User to run qtv as. Default to +# "%%QWUSER%%" created by the port. +# qtv_(instance_)?log (path): Console log file (default +# /var/log/${name}(_instance)?.log). +# qtv_(instance_)?qwdir (path): QuakeWorld root directory +# (default %%QWDIR%%). +# qtv_instances (str): Set to "" by default. +# If defined, list of instances to enable. + +. /etc/rc.subr + +case $0 in +/etc/rc*) + # during boot (shutdown) $0 is /etc/rc (/etc/rc.shutdown), + # so get the name of the script from $_file + name=$_file + ;; +*) + name=$0 + ;; +esac + +name=${name##*/} +rcvar="${name}_enable" + +load_rc_config "${name}" + +eval "${rcvar}=\${${rcvar}:-'NO'}" +eval "__args=\${${name}_args:-''}" +eval "__user=\${${name}_user:-'%%QWUSER%%'}" +eval "__log=\${${name}_log:-/var/log/${name}.log}" +eval "__qwdir=\${${name}_qwdir:-'%%QWDIR%%'}" +eval "${name}_chdir=${__qwdir}" +eval "__instances=\${${name}_instances:-''}" + +pidfiledir="/var/run" +pidfile="${pidfiledir}/${name}.pid" + +if [ -n "$2" ]; then + instance="$2" + load_rc_config ${name}_${instance} + case "${__instances}" in + "$2 "*|*" $2 "*|*" $2"|"$2") + eval "__args=\${${name}_${instance}_args:-${__args}}" + eval "__user=\${${name}_${instance}_user:-${__user}}" + eval "__log=\${${name}_${instance}_log:-/var/log/${name}_${instance}.log}" + eval "__qwdir=\${${name}_${instance}_qwdir:-${__qwdir}}" + eval "${name}_chdir=${__qwdir}" + pidfile="${pidfiledir}/${name}_${instance}.pid" + ;; + *) + err 1 "$2 not found in ${name}_instances" ;; + esac +else + if [ -n "${__instances}" -a -n "$1" ]; then + for instance in ${__instances}; do + eval "_enable=\${${name}_${instance}_enable}" + eval "__enable=\${_enable:-\${${name}_enable}}" + case "${__enable}" in + [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) + continue + ;; + [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) + ;; + *) + if [ -z "${_enable}" ]; then + _var=${name}_enable + else + _var=${name}_${instance}_enable + fi + warn "Bad value '${__enable}' for ${_var}. " \ + "Instance ${instance} skipped." + continue + ;; + esac + echo "===> ${name} instance: ${instance}" + %%PREFIX%%/etc/rc.d/${name} $1 ${instance} + retcode="$?" + if [ "0${retcode}" -eq 0 ]; then + success="${instance} ${success}" + else + failed="${instance} (retcode=${retcode}) ${failed}" + fi + done + echo "===> ${name} instances success: ${success}" + echo "===> ${name} instances failed: ${failed}" + exit 0 + fi +fi + +command="/usr/sbin/daemon" +command_args="-P ${pidfile} -u ${__user} -R 5 -f -H -o ${__log} -m 3 %%PREFIX%%/bin/qtv ${__args}" + +run_rc_command "$1" diff --git a/games/qtv/pkg-descr b/games/qtv/pkg-descr new file mode 100644 index 000000000000..867a84856823 --- /dev/null +++ b/games/qtv/pkg-descr @@ -0,0 +1,8 @@ +QTV is a QuakeWorld match broadcasting tool. + +The maximum number of players and spectators in QuakeWorld is 32. QTV allows +hundreds and even thousands of spectators to watch the game at the same time. +Also, a delay of about 10 seconds has been added so that spectators cannot +prompt players with information about opponents during the game via voice chats. +In such a dynamic game as QuakeWorld, a lot can change in a few seconds and the +information will be out of date. diff --git a/games/qtv/pkg-plist b/games/qtv/pkg-plist new file mode 100644 index 000000000000..60d2429c3db9 --- /dev/null +++ b/games/qtv/pkg-plist @@ -0,0 +1,102 @@ +bin/qtv +quake/qtv/levelshots/1on1.jpg +quake/qtv/levelshots/1on1r.jpg +quake/qtv/levelshots/2fort5.jpg +quake/qtv/levelshots/2fort5l.jpg +quake/qtv/levelshots/2fort5r.jpg +quake/qtv/levelshots/2tech4.jpg +quake/qtv/levelshots/32seq.jpg +quake/qtv/levelshots/32smooth.jpg +quake/qtv/levelshots/_notfound.jpg +quake/qtv/levelshots/a2.jpg +quake/qtv/levelshots/aerowalk.jpg +quake/qtv/levelshots/amphi.jpg +quake/qtv/levelshots/bam4.jpg +quake/qtv/levelshots/bases.jpg +quake/qtv/levelshots/battle.jpg +quake/qtv/levelshots/blitzkrieg2.jpg +quake/qtv/levelshots/border1.jpg +quake/qtv/levelshots/castle.jpg +quake/qtv/levelshots/cmt1b.jpg +quake/qtv/levelshots/cmt2.jpg +quake/qtv/levelshots/cmt3.jpg +quake/qtv/levelshots/cmt4.jpg +quake/qtv/levelshots/cmt5b.jpg +quake/qtv/levelshots/death32c.jpg +quake/qtv/levelshots/dm1.jpg +quake/qtv/levelshots/dm2.jpg +quake/qtv/levelshots/dm3.jpg +quake/qtv/levelshots/dm4.jpg +quake/qtv/levelshots/dm5.jpg +quake/qtv/levelshots/dm6.jpg +quake/qtv/levelshots/e1m1.jpg +quake/qtv/levelshots/e1m2.jpg +quake/qtv/levelshots/e1m3.jpg +quake/qtv/levelshots/e1m4.jpg +quake/qtv/levelshots/e1m5.jpg +quake/qtv/levelshots/e1m6.jpg +quake/qtv/levelshots/e1m7.jpg +quake/qtv/levelshots/e1m8.jpg +quake/qtv/levelshots/e2m1.jpg +quake/qtv/levelshots/e2m2.jpg +quake/qtv/levelshots/e2m3.jpg +quake/qtv/levelshots/e2m4.jpg +quake/qtv/levelshots/e2m5.jpg +quake/qtv/levelshots/e2m6.jpg +quake/qtv/levelshots/e2m7.jpg +quake/qtv/levelshots/e3m1.jpg +quake/qtv/levelshots/e3m2.jpg +quake/qtv/levelshots/e3m3.jpg +quake/qtv/levelshots/e3m4.jpg +quake/qtv/levelshots/e3m5.jpg +quake/qtv/levelshots/e3m6.jpg +quake/qtv/levelshots/e3m7.jpg +quake/qtv/levelshots/e4m1.jpg +quake/qtv/levelshots/e4m2.jpg +quake/qtv/levelshots/e4m3.jpg +quake/qtv/levelshots/e4m4.jpg +quake/qtv/levelshots/e4m5.jpg +quake/qtv/levelshots/e4m6.jpg +quake/qtv/levelshots/e4m7.jpg +quake/qtv/levelshots/e4m8.jpg +quake/qtv/levelshots/end.jpg +quake/qtv/levelshots/endif.jpg +quake/qtv/levelshots/engbat.jpg +quake/qtv/levelshots/genders2.jpg +quake/qtv/levelshots/hammer.jpg +quake/qtv/levelshots/hammerv2.jpg +quake/qtv/levelshots/hammerv3.jpg +quake/qtv/levelshots/hippos.jpg +quake/qtv/levelshots/hohoho.jpg +quake/qtv/levelshots/hunted.jpg +quake/qtv/levelshots/mbases.jpg +quake/qtv/levelshots/pkeg1.jpg +quake/qtv/levelshots/povdmm4.jpg +quake/qtv/levelshots/qffldm2.jpg +quake/qtv/levelshots/qffldm5.jpg +quake/qtv/levelshots/rock1.jpg +quake/qtv/levelshots/rs_zz1.jpg +quake/qtv/levelshots/schloss.jpg +quake/qtv/levelshots/skull.jpg +quake/qtv/levelshots/sniprwar.jpg +quake/qtv/levelshots/spinev2.jpg +quake/qtv/levelshots/start.jpg +quake/qtv/levelshots/ukcldm2.jpg +quake/qtv/levelshots/vote40.jpg +quake/qtv/levelshots/well6.jpg +quake/qtv/levelshots/xmastree.jpg +quake/qtv/levelshots/xpress3.jpg +quake/qtv/levelshots/ztndm1.jpg +quake/qtv/levelshots/ztndm2.jpg +quake/qtv/levelshots/ztndm3.jpg +quake/qtv/levelshots/ztndm4.jpg +quake/qtv/levelshots/ztndm5.jpg +quake/qtv/levelshots/ztndm6.jpg +@sample(,%%QWGROUP%%,0640) quake/qtv/listip.cfg.sample +@sample(,%%QWGROUP%%,0640) quake/qtv/qtv.cfg.sample +quake/qtv/qtvbg01.png +quake/qtv/save.png +quake/qtv/script.js +quake/qtv/stream.png +quake/qtv/style.css +%%PORTDOCS%%%%DOCSDIR%%/README.1ST |
