Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions game/tc2/gameinfo_server.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"GameInfo"
{
game "Team Comtress 2"
type multiplayer_only
nomodels 1
nohimodel 1
nocrosshair 0
hidden_maps
{
"test_speakers" 1
"test_hardware" 1
}
nodegraph 0
GameData "tf.fgd"
AdditionalLocalization "tf"
InstancePath "maps/instances/"
advcrosshair 1
supportsvr 0
ReplayRequired 1

DependsOnAppID 440

FileSystem
{
SteamAppId 243750

SearchPaths
{
// First, mount all user customizations. This will search for VPKs and subfolders
// and mount them in alphabetical order. The easiest way to distribute a mod is to
// pack up the custom content into a VPK. To "install" a mod, just drop it in this
// folder.
//
// Note that this folder is scanned only when the game is booted.
game+mod+custom_mod tc2/custom/*
// Enable this if you want to load your TF custom content.
//game+mod |appid_440|tf/custom/*

// Now search loose files. We'll set the directory containing the gameinfo.txt file
// as the first "mod" search path (after any user customizations). This is also the one
// that's used when writing to the "mod" path.
mod+mod_write |all_source_engine_paths|tc2
game+game_write |all_source_engine_paths|tc2
default_write_path |all_source_engine_paths|tc2
gamebin |all_source_engine_paths|tc2/bin

// We search VPK files before ordinary folders, because most files will be found in
// VPK and we can avoid making thousands of file system calls to attempt to open files
// in folders where they don't exist. (Searching a VPK is much faster than making an operating
// system call.)
game_lv |all_source_engine_paths|tf/tf2_lv.vpk
game+mod |all_source_engine_paths|tf/tf2_textures.vpk
game+mod |all_source_engine_paths|tf/tf2_sound_vo_english.vpk
game+mod |all_source_engine_paths|tf/tf2_sound_misc.vpk
game+mod+vgui |all_source_engine_paths|tf/tf2_misc.vpk
game |all_source_engine_paths|hl2/hl2_textures.vpk
game |all_source_engine_paths|hl2/hl2_sound_vo_english.vpk
game |all_source_engine_paths|hl2/hl2_sound_misc.vpk
game+vgui |all_source_engine_paths|hl2/hl2_misc.vpk
platform+vgui |all_source_engine_paths|platform/platform_misc.vpk

// Last, mount in shared HL2 and TF2 loose files
// game |all_source_engine_paths|tf
// game |all_source_engine_paths|hl2
// platform |all_source_engine_paths|platform


// Random files downloaded from gameservers go into a seperate directory, so
// that it's easy to keep those files segregated from the official game files
// or customizations intentially installed by the user.
//
// This directory is searched LAST. If you visit a server and download
// a custom model, etc, we don't want that file to override the default
// game file indefinitely (after you have left the server). Servers CAN have
// custom content that overrides the default game files, it just needs to be
// packed up in the .bsp file so that it will be mounted as a map search pack.
// The map search pack is mounted at the top of the search path list,
// but only while you are connected that server and on that map.
game+download tc2/download
}
}
ToolsEnvironment
{
"Engine" "Source"
"UseVPLATFORM" "1"
"PythonVersion" "2.7"
"PythonHomeDisable" "1"
}
}
87 changes: 87 additions & 0 deletions src/builddedicatedserver
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env bash

set -euo pipefail

script=$(readlink -f -- "$0")
pushd "$(dirname -- "$script")" > /dev/null

source sdk_container
run_in_sniper "$@"
export CCACHE_SLOPPINESS="pch_defines,time_macros"
export VPC_ENABLE_CCACHE="1"
ccache -z

if [ $# -eq 0 ]; then
export VPC_NINJA_BUILD_MODE="release"
else
if [[ "$1" == "debug" ]]; then
export VPC_NINJA_BUILD_MODE="debug"
elif [[ "$1" == "release" ]]; then
export VPC_NINJA_BUILD_MODE="release"
else
echo "Usage: $0 [debug|release]"
exit 1
fi
fi

solution_out="_vpc_/ninja/sdk_dedicated_$VPC_NINJA_BUILD_MODE"

# Dir of interest in /my_mod/src
DIR="./lib/public/linux64"

# Check if the serversided libraries are provided in catalog files check
SERVER_LIBS=("libtier0_srv.so" "libvstdlib_srv.so")

for file in "${SERVER_LIBS[@]}"; do
if [[ ! -f "$DIR/$file" ]]; then
echo "Error: Required file $DIR/$file is missing!"
echo "Please, provide them from your dedicated server install."
exit 1
fi
done

# Directories for symlinking server libraries in
DIRS=("./lib/public/linux64" "./lib/common/linux64")

# Copy all the *.a -> *_srv.a files from lib catalog before compiling
for dir in "${DIRS[@]}"; do
for file in "$dir"/*.a; do
[[ -e "$file" ]] || continue
base_name=$(basename -- "$file" .a)
copy="$dir/${base_name}_srv.a"

if [[ -f "$copy" ]]; then
echo "File already exists, skipping: $copy"
continue
fi

cp "$file" "$copy"
echo "Copied: $file -> $copy"
done
done


if [[ ! -e "$solution_out.ninja" ]]; then
devtools/bin/vpc /tf /linux64 /ninja /define:SOURCESDK +dedicated /dedicated /mksln "$solution_out"

# Generate compile commands.
ninja -f "$solution_out.ninja" -t compdb > compile_commands.json
# Remove some unsupported clang commands.
sed -i 's/-fpredictive-commoning//g; s/-fvar-tracking-assignments//g' compile_commands.json
sed -i 's|/my_mod/src|.|g' compile_commands.json
fi

ninja -f "$solution_out.ninja" -j$(nproc)
ccache -s

# Removing copied files
for dir in "${DIRS[@]}"; do
for copy in "$dir"/*_srv.a; do
if [[ -f "$copy" ]]; then
echo "Deleting copied file: $copy"
rm "$copy"
fi
done
done

popd
37 changes: 22 additions & 15 deletions src/game/server/tf/tf_gc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4068,6 +4068,13 @@ void CTFGCServerSystem::WebapiEquipmentThink()
WebapiEquipmentThinkRequest( m_mapEquipmentRequests.Key( i ), m_mapEquipmentRequests.Element( i ) );
}
}

#ifdef DEDICATED
#define STEAM_HTTP_INTERFACE SteamGameServerHTTP
#else
#define STEAM_HTTP_INTERFACE SteamHTTP
#endif

void CTFGCServerSystem::WebapiEquipmentThinkRequest( CSteamID steamID, WebapiEquipmentState_t* pState )
{
Assert( pState );
Expand All @@ -4093,7 +4100,7 @@ void CTFGCServerSystem::WebapiEquipmentThinkRequest( CSteamID steamID, WebapiEqu

if ( state.m_hEquipmentRequest != INVALID_HTTPREQUEST_HANDLE )
{
SteamHTTP()->ReleaseHTTPRequest( state.m_hEquipmentRequest );
STEAM_HTTP_INTERFACE()->ReleaseHTTPRequest( state.m_hEquipmentRequest );
state.m_hEquipmentRequest = INVALID_HTTPREQUEST_HANDLE;
}

Expand All @@ -4117,33 +4124,33 @@ void CTFGCServerSystem::WebapiEquipmentThinkRequest( CSteamID steamID, WebapiEqu
Assert( state.m_pKVCurrentRequest != nullptr );
KeyValues* pKV = state.m_pKVCurrentRequest;

if ( !SteamHTTP() )
if ( !STEAM_HTTP_INTERFACE() )
return;

// Request inventory from teamfortress.com webapi
CFmtStr strUrl( "%swebapi/ISDK/GetEquipment/v0001", GetWebBaseUrl() );

state.m_EquipmentRequestCompleted.Cancel();
state.m_hEquipmentRequest = SteamHTTP()->CreateHTTPRequest( k_EHTTPMethodGET, strUrl.Get() );
state.m_hEquipmentRequest = STEAM_HTTP_INTERFACE()->CreateHTTPRequest( k_EHTTPMethodGET, strUrl.Get() );
if ( state.m_hEquipmentRequest == INVALID_HTTPREQUEST_HANDLE )
{
// try again next frame
return;
}

// This mod's appid (NOT tf2's appid)
SteamHTTP()->SetHTTPRequestGetOrPostParameter( state.m_hEquipmentRequest, "appid", CNumStr( engine->GetAppID() ) );
STEAM_HTTP_INTERFACE()->SetHTTPRequestGetOrPostParameter( state.m_hEquipmentRequest, "appid", CNumStr( engine->GetAppID() ) );

// Item list
SteamHTTP()->SetHTTPRequestGetOrPostParameter( state.m_hEquipmentRequest, "msg", pKV->GetString( "msg", nullptr ) );
STEAM_HTTP_INTERFACE()->SetHTTPRequestGetOrPostParameter( state.m_hEquipmentRequest, "msg", pKV->GetString( "msg", nullptr ) );

// Authentication token
SteamHTTP()->SetHTTPRequestGetOrPostParameter( state.m_hEquipmentRequest, "ticket", pKV->GetString( "ticket", nullptr ) );
STEAM_HTTP_INTERFACE()->SetHTTPRequestGetOrPostParameter( state.m_hEquipmentRequest, "ticket", pKV->GetString( "ticket", nullptr ) );

if ( GetUniverse() != k_EUniversePublic )
{
// use beta tf2 appid on non public universes
SteamHTTP()->SetHTTPRequestGetOrPostParameter( state.m_hEquipmentRequest, "game_appid", "810" );
STEAM_HTTP_INTERFACE()->SetHTTPRequestGetOrPostParameter( state.m_hEquipmentRequest, "game_appid", "810" );
}

// Is there a way we can validate the existing so cache? We could only request the new items.
Expand All @@ -4156,11 +4163,11 @@ void CTFGCServerSystem::WebapiEquipmentThinkRequest( CSteamID steamID, WebapiEqu
//CGCClientSharedObjectCache* pExistingSOCache = GetSOCache( steamID );
//if ( pExistingSOCache && pExistingSOCache->BIsSubscribed() )
//{
// SteamHTTP()->SetHTTPRequestGetOrPostParameter( state.m_hInventoryRequest, "version", CNumStr( pExistingSOCache->GetVersion() ) );
// STEAM_HTTP_INTERFACE()->SetHTTPRequestGetOrPostParameter( state.m_hInventoryRequest, "version", CNumStr( pExistingSOCache->GetVersion() ) );
//}

SteamAPICall_t callResult;
if ( !SteamHTTP()->SendHTTPRequest( state.m_hEquipmentRequest, &callResult ) )
if ( !STEAM_HTTP_INTERFACE()->SendHTTPRequest( state.m_hEquipmentRequest, &callResult ) )
{
state.Backoff();
return;
Expand Down Expand Up @@ -4229,36 +4236,36 @@ void CTFGCServerSystem::OnWebapiEquipmentReceived( CSteamID steamID, HTTPRequest
state.Backoff();
state.m_eState = kWebapiEquipmentState_RequestInventory;

if ( !SteamHTTP() )
if ( !STEAM_HTTP_INTERFACE() )
return;

if( bIOFailure || !pInfo || state.m_hEquipmentRequest != pInfo->m_hRequest )
{
Assert( false );
if( state.m_hEquipmentRequest != INVALID_HTTPREQUEST_HANDLE )
{
SteamHTTP()->ReleaseHTTPRequest( state.m_hEquipmentRequest );
STEAM_HTTP_INTERFACE()->ReleaseHTTPRequest( state.m_hEquipmentRequest );
}
return;
}

// request failed -- backoff and retry
if ( !pInfo->m_bRequestSuccessful || pInfo->m_eStatusCode != k_EHTTPStatusCode200OK )
{
SteamHTTP()->ReleaseHTTPRequest( state.m_hEquipmentRequest );
STEAM_HTTP_INTERFACE()->ReleaseHTTPRequest( state.m_hEquipmentRequest );
return;
}

// Extract the result
uint32 unBytes;
Verify( SteamHTTP()->GetHTTPResponseBodySize( pInfo->m_hRequest, &unBytes ) );
Verify( STEAM_HTTP_INTERFACE()->GetHTTPResponseBodySize( pInfo->m_hRequest, &unBytes ) );
CUtlBuffer bufInventory;
bufInventory.EnsureCapacity( unBytes );
bufInventory.SeekPut( CUtlBuffer::SEEK_HEAD, unBytes );
Verify( SteamHTTP()->GetHTTPResponseBodyData( pInfo->m_hRequest, ( uint8* )bufInventory.Base(), unBytes ) );
Verify( STEAM_HTTP_INTERFACE()->GetHTTPResponseBodyData( pInfo->m_hRequest, ( uint8* )bufInventory.Base(), unBytes ) );

// We're done with the request now
SteamHTTP()->ReleaseHTTPRequest( pInfo->m_hRequest );
STEAM_HTTP_INTERFACE()->ReleaseHTTPRequest( pInfo->m_hRequest );

// Parse it to json and extract the data
GCSDK::CWebAPIValues* pValues = GCSDK::CWebAPIValues::ParseJSON( bufInventory );
Expand Down