Skip to content
Merged
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
57 changes: 57 additions & 0 deletions build_vs2026.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
@echo off
rem ---------------------------------------------------------------------------
rem Build SteamworksPy64.dll against the vendored Steamworks SDK (library\sdk)
rem using whatever Visual Studio (with C++ x64 tools) is installed.
rem
rem Unlike the upstream build_win_64.bat this does NOT assume the "BuildTools"
rem edition / old install layout -- it discovers the install via vswhere and
rem calls vcvars64.bat. No argument required.
rem ---------------------------------------------------------------------------
setlocal enableextensions
cd /d "%~dp0"

echo [*] Locating Visual Studio C++ toolchain
set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
if not exist "%VSWHERE%" (
echo [!] vswhere.exe not found at "%VSWHERE%"
exit /b 5
)
set "VSINSTALL="
for /f "usebackq delims=" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSINSTALL=%%i"
if not defined VSINSTALL (
echo [!] No Visual Studio install with the C++ x64 tools was found.
exit /b 5
)
echo [*] Using: %VSINSTALL%
call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" >nul || (echo [!] vcvars64 failed & exit /b 5)

echo [*] Checking SDK prerequisites
if not exist "library\sdk\steam\steam_api.h" (echo [!] missing library\sdk\steam\*.h & exit /b 5)
if not exist "library\sdk\redist\steam_api64.dll" (echo [!] missing library\sdk\redist\steam_api64.dll & exit /b 5)
if not exist "library\sdk\redist\steam_api64.lib" (echo [!] missing library\sdk\redist\steam_api64.lib & exit /b 5)

set "DIRNAME=_build_%RANDOM%"
echo [*] Building in %DIRNAME%
mkdir "%DIRNAME%"
copy /y "library\SteamworksPy.cpp" "%DIRNAME%\SteamworksPy.cpp" >nul
copy /y "library\sdk\redist\steam_api64.dll" "%DIRNAME%\" >nul
copy /y "library\sdk\redist\steam_api64.lib" "%DIRNAME%\" >nul
mklink /J "%DIRNAME%\sdk" "%CD%\library\sdk" >nul

pushd "%DIRNAME%"
echo [*] Compiling SteamworksPy64.dll
cl.exe /nologo /O2 /EHsc /D_USRDLL /D_WINDLL SteamworksPy.cpp steam_api64.lib /link /DLL /OUT:SteamworksPy64.dll 2>&1
set "RC=%ERRORLEVEL%"
popd

if "%RC%"=="0" (
if not exist "redist\windows" mkdir "redist\windows"
copy /y "%DIRNAME%\SteamworksPy64.dll" "redist\windows\SteamworksPy64.dll" >nul
echo [*] OK -^> redist\windows\SteamworksPy64.dll
) else (
echo [!] Build FAILED with code %RC%
)

echo [*] Cleanup
rmdir /s /q "%DIRNAME%"
exit /b %RC%
187 changes: 167 additions & 20 deletions library/SteamworksPy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,11 @@ typedef void(*RemoteStorageUnsubscribeFileResultCallback_t)(SubscriptionResult);
typedef void(*LeaderboardFindResultCallback_t)(LeaderboardFindResult_t);
typedef void(*MicroTxnAuthorizationResponseCallback_t)(MicroTxnAuthorizationResponse_t);
typedef void(*SteamUGCQueryCompletedCallback_t)(SteamUGCQueryCompleted_t);
typedef void(*GetAppDependenciesResultCallback_t)(GetAppDependenciesResult_t);
typedef void(*DownloadItemResultCallback_t)(DownloadItemResult_t);
typedef void(*AddUGCDependencyResultCallback_t)(AddUGCDependencyResult_t);
typedef void(*RemoveUGCDependencyResultCallback_t)(RemoveUGCDependencyResult_t);
typedef void(*AddAppDependencyResultCallback_t)(AddAppDependencyResult_t);
typedef void(*RemoveAppDependencyResultCallback_t)(RemoveAppDependencyResult_t);

//-----------------------------------------------
// Workshop Class
Expand All @@ -120,17 +123,23 @@ class Workshop {
RemoteStorageSubscribeFileResultCallback_t _pyItemSubscribedCallback;
RemoteStorageUnsubscribeFileResultCallback_t _pyItemUnsubscribedCallback;
SteamUGCQueryCompletedCallback_t _pyQueryCompletedCallback;
GetAppDependenciesResultCallback_t _pyGetAppDependenciesCallback;
DownloadItemResultCallback_t _pyDownloadItemCallback;
AddUGCDependencyResultCallback_t _pyAddDependencyCallback = nullptr;
RemoveUGCDependencyResultCallback_t _pyRemoveDependencyCallback = nullptr;
AddAppDependencyResultCallback_t _pyAddAppDependencyCallback = nullptr;
RemoveAppDependencyResultCallback_t _pyRemoveAppDependencyCallback = nullptr;

CCallResult <Workshop, CreateItemResult_t> _itemCreatedCallback;
CCallResult <Workshop, SubmitItemUpdateResult_t> _itemUpdatedCallback;
CCallResult <Workshop, GetAppDependenciesResult_t> _getAppDependenciesCallback;
CCallResult <Workshop, RemoteStorageSubscribePublishedFileResult_t> _itemSubscribedCallback;
CCallResult <Workshop, RemoteStorageUnsubscribePublishedFileResult_t> _itemUnsubscribedCallback;
CCallResult <Workshop, SteamUGCQueryCompleted_t> _queryCompletedCallback;
CCallResult <Workshop, GetAppDependenciesResult_t> _getAppDependenciesCallback;
CCallResult <Workshop, DownloadItemResult_t> _downloadItemCallback;
CCallResult <Workshop, AddUGCDependencyResult_t> _addDependencyCallback;
CCallResult <Workshop, RemoveUGCDependencyResult_t> _removeDependencyCallback;
CCallResult <Workshop, AddAppDependencyResult_t> _addAppDependencyCallback;
CCallResult <Workshop, RemoveAppDependencyResult_t> _removeAppDependencyCallback;

CCallback <Workshop, ItemInstalled_t> _itemInstalledCallback;

Expand Down Expand Up @@ -207,17 +216,50 @@ class Workshop {
_queryCompletedCallback.Set(queryRequestCall, this, &Workshop::OnQueryCompleted);
}

void GetAppDependencies(PublishedFileId_t publishedFileID) {
SteamAPICall_t getAppDependenciesCall = SteamUGC()->GetAppDependencies(publishedFileID);
_getAppDependenciesCallback.Set(getAppDependenciesCall, this, &Workshop::OnGetAppDependencies);
}

bool DownloadItem(PublishedFileId_t publishedFileID, bool bHighPriority) {
SteamAPICall_t downloadItemCall = SteamUGC()->DownloadItem(publishedFileID, bHighPriority);
_downloadItemCallback.Set(downloadItemCall, this, &Workshop::OnDownloadItem);
return true; // Returns true if successfully queued
}

void SetAddDependencyResultCallback(AddUGCDependencyResultCallback_t callback) {
_pyAddDependencyCallback = callback;
}

void SetRemoveDependencyResultCallback(RemoveUGCDependencyResultCallback_t callback) {
_pyRemoveDependencyCallback = callback;
}

void SetAddAppDependencyResultCallback(AddAppDependencyResultCallback_t callback) {
_pyAddAppDependencyCallback = callback;
}

void SetRemoveAppDependencyResultCallback(RemoveAppDependencyResultCallback_t callback) {
_pyRemoveAppDependencyCallback = callback;
}

// Workshop-to-workshop "Required Item" relationship (parent requires child).
void AddDependency(PublishedFileId_t parentID, PublishedFileId_t childID) {
SteamAPICall_t call = SteamUGC()->AddDependency(parentID, childID);
_addDependencyCallback.Set(call, this, &Workshop::OnAddDependency);
}

void RemoveDependency(PublishedFileId_t parentID, PublishedFileId_t childID) {
SteamAPICall_t call = SteamUGC()->RemoveDependency(parentID, childID);
_removeDependencyCallback.Set(call, this, &Workshop::OnRemoveDependency);
}

// App (game/DLC) dependency on a workshop item.
void AddAppDependency(PublishedFileId_t publishedFileID, AppId_t appID) {
SteamAPICall_t call = SteamUGC()->AddAppDependency(publishedFileID, appID);
_addAppDependencyCallback.Set(call, this, &Workshop::OnAddAppDependency);
}

void RemoveAppDependency(PublishedFileId_t publishedFileID, AppId_t appID) {
SteamAPICall_t call = SteamUGC()->RemoveAppDependency(publishedFileID, appID);
_removeAppDependencyCallback.Set(call, this, &Workshop::OnRemoveAppDependency);
}

private:
void OnWorkshopItemCreated(CreateItemResult_t *createItemResult, bool bIOFailure) {
if (_pyItemCreatedCallback != nullptr) {
Expand Down Expand Up @@ -273,17 +315,35 @@ class Workshop {
}
}

void OnGetAppDependencies(GetAppDependenciesResult_t *result, bool bIOFailure) {
if (_pyGetAppDependenciesCallback != nullptr) {
_pyGetAppDependenciesCallback(*result);
}
}

void OnDownloadItem(DownloadItemResult_t *result, bool bIOFailure) {
if (_pyDownloadItemCallback != nullptr) {
_pyDownloadItemCallback(*result);
}
}

void OnAddDependency(AddUGCDependencyResult_t *result, bool bIOFailure) {
if (_pyAddDependencyCallback != nullptr) {
_pyAddDependencyCallback(*result);
}
}

void OnRemoveDependency(RemoveUGCDependencyResult_t *result, bool bIOFailure) {
if (_pyRemoveDependencyCallback != nullptr) {
_pyRemoveDependencyCallback(*result);
}
}

void OnAddAppDependency(AddAppDependencyResult_t *result, bool bIOFailure) {
if (_pyAddAppDependencyCallback != nullptr) {
_pyAddAppDependencyCallback(*result);
}
}

void OnRemoveAppDependency(RemoveAppDependencyResult_t *result, bool bIOFailure) {
if (_pyRemoveAppDependencyCallback != nullptr) {
_pyRemoveAppDependencyCallback(*result);
}
}
};

static Workshop workshop;
Expand Down Expand Up @@ -1594,25 +1654,112 @@ SW_PY void Workshop_SetGetAppDependenciesCallback(GetAppDependenciesResultCallba
workshop.SetGetAppDependenciesCallback(callback);
}

SW_PY void Workshop_GetAppDependencies(PublishedFileId_t publishedFileID) {
SW_PY void Workshop_SetDownloadItemCallback(DownloadItemResultCallback_t callback) {
if (SteamUGC() == NULL) {
return;
}
workshop.GetAppDependencies(publishedFileID);
workshop.SetDownloadItemCallback(callback);
}

SW_PY void Workshop_SetDownloadItemCallback(DownloadItemResultCallback_t callback) {
SW_PY bool Workshop_DownloadItem(PublishedFileId_t publishedFileID, bool bHighPriority) {
if (SteamUGC() == NULL) {
return false;
}
return workshop.DownloadItem(publishedFileID, bHighPriority);
}

// --- Required Items (workshop-to-workshop dependencies) -------------------
SW_PY void Workshop_SetAddDependencyResultCallback(AddUGCDependencyResultCallback_t callback) {
if (SteamUGC() == NULL) {
return;
}
workshop.SetDownloadItemCallback(callback);
workshop.SetAddDependencyResultCallback(callback);
}

SW_PY bool Workshop_DownloadItem(PublishedFileId_t publishedFileID, bool bHighPriority) {
SW_PY void Workshop_AddDependency(PublishedFileId_t parentID, PublishedFileId_t childID) {
if (SteamUGC() == NULL) {
return;
}
workshop.AddDependency(parentID, childID);
}

SW_PY void Workshop_SetRemoveDependencyResultCallback(RemoveUGCDependencyResultCallback_t callback) {
if (SteamUGC() == NULL) {
return;
}
workshop.SetRemoveDependencyResultCallback(callback);
}

SW_PY void Workshop_RemoveDependency(PublishedFileId_t parentID, PublishedFileId_t childID) {
if (SteamUGC() == NULL) {
return;
}
workshop.RemoveDependency(parentID, childID);
}

// --- App dependencies (item depends on a game/DLC) ------------------------
SW_PY void Workshop_SetAddAppDependencyResultCallback(AddAppDependencyResultCallback_t callback) {
if (SteamUGC() == NULL) {
return;
}
workshop.SetAddAppDependencyResultCallback(callback);
}

SW_PY void Workshop_AddAppDependency(PublishedFileId_t publishedFileID, AppId_t appID) {
if (SteamUGC() == NULL) {
return;
}
workshop.AddAppDependency(publishedFileID, appID);
}

SW_PY void Workshop_SetRemoveAppDependencyResultCallback(RemoveAppDependencyResultCallback_t callback) {
if (SteamUGC() == NULL) {
return;
}
workshop.SetRemoveAppDependencyResultCallback(callback);
}

SW_PY void Workshop_RemoveAppDependency(PublishedFileId_t publishedFileID, AppId_t appID) {
if (SteamUGC() == NULL) {
return;
}
workshop.RemoveAppDependency(publishedFileID, appID);
}

// --- Synchronous item-update setters (no async callback) ------------------
SW_PY bool Workshop_AddItemKeyValueTag(UGCUpdateHandle_t updateHandle, const char *pKey, const char *pValue) {
if (SteamUGC() == NULL) {
return false;
}
return workshop.DownloadItem(publishedFileID, bHighPriority);
return SteamUGC()->AddItemKeyValueTag(updateHandle, pKey, pValue);
}

SW_PY bool Workshop_RemoveItemKeyValueTags(UGCUpdateHandle_t updateHandle, const char *pKey) {
if (SteamUGC() == NULL) {
return false;
}
return SteamUGC()->RemoveItemKeyValueTags(updateHandle, pKey);
}

SW_PY bool Workshop_RemoveAllItemKeyValueTags(UGCUpdateHandle_t updateHandle) {
if (SteamUGC() == NULL) {
return false;
}
return SteamUGC()->RemoveAllItemKeyValueTags(updateHandle);
}

SW_PY bool Workshop_AddContentDescriptor(UGCUpdateHandle_t updateHandle, int descid) {
if (SteamUGC() == NULL) {
return false;
}
return SteamUGC()->AddContentDescriptor(updateHandle, (EUGCContentDescriptorID) descid);
}

SW_PY bool Workshop_RemoveContentDescriptor(UGCUpdateHandle_t updateHandle, int descid) {
if (SteamUGC() == NULL) {
return false;
}
return SteamUGC()->RemoveContentDescriptor(updateHandle, (EUGCContentDescriptorID) descid);
}

//-----------------------------------------------
Expand Down
Binary file modified redist/windows/SteamworksPy64.dll
Binary file not shown.
Loading