Skip to content

Add support for querying Steam Workshop items #110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
43 changes: 43 additions & 0 deletions library/SteamworksPy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ typedef void(*RemoteStorageSubscribeFileResultCallback_t)(SubscriptionResult);
typedef void(*RemoteStorageUnsubscribeFileResultCallback_t)(SubscriptionResult);
typedef void(*LeaderboardFindResultCallback_t)(LeaderboardFindResult_t);
typedef void(*MicroTxnAuthorizationResponseCallback_t)(MicroTxnAuthorizationResponse_t);
typedef void(*SteamUGCQueryCompletedCallback_t)(SteamUGCQueryCompleted_t);

//-----------------------------------------------
// Workshop Class
Expand All @@ -106,11 +107,13 @@ class Workshop {
ItemInstalledCallback_t _pyItemInstalledCallback;
RemoteStorageSubscribeFileResultCallback_t _pyItemSubscribedCallback;
RemoteStorageUnsubscribeFileResultCallback_t _pyItemUnsubscribedCallback;
SteamUGCQueryCompletedCallback_t _pyQueryCompletedCallback;

CCallResult <Workshop, CreateItemResult_t> _itemCreatedCallback;
CCallResult <Workshop, SubmitItemUpdateResult_t> _itemUpdatedCallback;
CCallResult <Workshop, RemoteStorageSubscribePublishedFileResult_t> _itemSubscribedCallback;
CCallResult <Workshop, RemoteStorageUnsubscribePublishedFileResult_t> _itemUnsubscribedCallback;
CCallResult <Workshop, SteamUGCQueryCompleted_t> _queryCompletedCallback;

CCallback <Workshop, ItemInstalled_t> _itemInstalledCallback;

Expand Down Expand Up @@ -140,6 +143,10 @@ class Workshop {
_pyItemUnsubscribedCallback = callback;
}

void SetQueryCompletedCallback(SteamUGCQueryCompletedCallback_t callback) {
_pyQueryCompletedCallback = callback;
}

void CreateItem(AppId_t consumerAppId, EWorkshopFileType fileType) {
//TODO: Check if fileType is a valid value?
SteamAPICall_t createItemCall = SteamUGC()->CreateItem(consumerAppId, fileType);
Expand All @@ -161,6 +168,11 @@ class Workshop {
_itemUnsubscribedCallback.Set(unsubscribeItemCall, this, &Workshop::OnItemUnsubscribed);
}

void SendQueryRequest(UGCQueryHandle_t queryHandle) {
SteamAPICall_t queryRequestCall = SteamUGC()->SendQueryUGCRequest(queryHandle);
_queryCompletedCallback.Set(queryRequestCall, this, &Workshop::OnQueryCompleted);
}

private:
void OnWorkshopItemCreated(CreateItemResult_t *createItemResult, bool bIOFailure) {
if (_pyItemCreatedCallback != nullptr) {
Expand Down Expand Up @@ -193,6 +205,12 @@ class Workshop {
_pyItemUnsubscribedCallback(result);
}
}

void OnQueryCompleted(SteamUGCQueryCompleted_t *queryCompletedResult, bool bIOFailure) {
if (_pyQueryCompletedCallback != nullptr) {
_pyQueryCompletedCallback(*queryCompletedResult);
}
}
};

static Workshop workshop;
Expand Down Expand Up @@ -1457,6 +1475,31 @@ SW_PY void Workshop_SuspendDownloads(bool bSuspend) {
SteamUGC()->SuspendDownloads(bSuspend);
}

SW_PY UGCQueryHandle_t Workshop_CreateQueryUGCDetailsRequest(PublishedFileId_t * pvecPublishedFileID, uint32 unNumPublishedFileIDs) {
return SteamUGC()->CreateQueryUGCDetailsRequest(pvecPublishedFileID, unNumPublishedFileIDs);
}

SW_PY void Workshop_SetQueryCompletedCallback(SteamUGCQueryCompletedCallback_t callback) {
if (SteamUGC() == NULL) {
return;
}
workshop.SetQueryCompletedCallback(callback);
}

SW_PY void Workshop_SendQueryUGCRequest(UGCQueryHandle_t handle) {
if(SteamUGC() == NULL){
return;
}
workshop.SendQueryRequest(handle);
}

SW_PY bool Workshop_GetQueryUGCResult(UGCQueryHandle_t handle, uint32 index, SteamUGCDetails_t * pDetails) {
if(SteamUGC() == NULL){
return false;
}
return SteamUGC()->GetQueryUGCResult(handle, index, pDetails);
}

//-----------------------------------------------
// Steam Leaderboard
//-----------------------------------------------
Expand Down
58 changes: 58 additions & 0 deletions steamworks/interfaces/workshop.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ class SteamWorkshop(object):
_ItemInstalled_t = CFUNCTYPE(None, ItemInstalled_t)
_RemoteStorageSubscribePublishedFileResult_t = CFUNCTYPE(None, SubscriptionResult)
_RemoteStorageUnsubscribePublishedFileResult_t = CFUNCTYPE(None, SubscriptionResult)
_SteamUGCQueryCompleted_t = CFUNCTYPE(None, SteamUGCQueryCompleted_t)

_CreateItemResult = None
_SubmitItemUpdateResult = None
_ItemInstalled = None
_RemoteStorageSubscribePublishedFileResult = None
_RemoteStorageUnsubscribePublishedFileResult = None
_SteamUGCQueryCompleted = None


def __init__(self, steam: object):
Expand Down Expand Up @@ -376,3 +378,59 @@ def GetItemDownloadInfo(self, published_file_id: int) -> dict:
}

return {}


def CreateQueryUGCDetailsRequest(self, published_file_ids: list) -> int:
"""Create UGC item details query request

:param published_file_ids: int list
:return: int
"""
published_files_c = (c_uint64 * len(published_file_ids))()
for index, published_file_id in enumerate(published_file_ids):
published_files_c[index] = c_uint64(published_file_id)

return self.steam.Workshop_CreateQueryUGCDetailsRequest(published_files_c, len(published_file_ids))


def SetQueryUGCRequestCallback(self, callback: object) -> bool:
"""Set callback for UGC query

:param callback: callable
:return: bool
"""
self._SteamUGCQueryCompleted = SteamWorkshop._SteamUGCQueryCompleted_t(callback)
self.steam.Workshop_SetQueryCompletedCallback(self._SteamUGCQueryCompleted)
return True


def SendQueryUGCRequest(self, handle: int, callback: object = None, override_callback: bool = False) -> None:
"""Create UGC item details query request

:param handle: query handle
:param callback: callable
:param override_callback: bool
:return:
"""
if override_callback:
self.SetQueryUGCRequestCallback(callback)

elif callback and not self._SteamUGCQueryCompleted:
self.SetQueryUGCRequestCallback(callback)

if self._SteamUGCQueryCompleted is None:
raise SetupRequired('Call `SetQueryUGCRequestCallback` first or supply a `callback`')

self.steam.Workshop_SendQueryUGCRequest(handle)


def GetQueryUGCResult(self, handle: int, index: int) -> SteamUGCDetails_t:
"""Create UGC item details query request

:param handle: query handle
:param index: int
:return: SteamUGCDetails_t
"""
details = SteamUGCDetails_t()
self.steam.Workshop_GetQueryUGCResult(handle, index, byref(details))
return details
15 changes: 15 additions & 0 deletions steamworks/methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,21 @@ class InputDigitalActionData_t(Structure):
'restype': None,
'argtypes': [c_uint64]
},
'Workshop_CreateQueryUGCDetailsRequest': {
'restype': c_uint64,
'argtypes': [POINTER(c_uint64), c_uint32]
},
'Workshop_SetQueryCompletedCallback': {
'restype': None,
'argtypes': [MAKE_CALLBACK(None, structs.SteamUGCQueryCompleted_t)]
},
'Workshop_SendQueryUGCRequest': {
'argtypes': [c_uint64]
},
'Workshop_GetQueryUGCResult': {
'restype': bool,
'argtypes': [c_uint64, c_uint32, POINTER(structs.SteamUGCDetails_t)]
},
'MicroTxn_SetAuthorizationResponseCallback': {
'restype': None,
'argtypes': [MAKE_CALLBACK(None, structs.MicroTxnAuthorizationResponse_t)]
Expand Down
42 changes: 42 additions & 0 deletions steamworks/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,48 @@ class SubscriptionResult(Structure):
("publishedFileId", c_uint64)
]


class SteamUGCQueryCompleted_t(Structure):
_fields_ = [
("handle", c_uint64),
("result", c_int),
("numResultsReturned", c_uint32),
("totalMatchingResults", c_uint32),
("cachedData", c_bool)
]


class SteamUGCDetails_t(Structure):
_fields_ = [
("publishedFileId", c_uint64),
("result", c_int),
("fileType", c_int),
("creatorAppID", c_uint32),
("consumerAppID", c_uint32),
("title", c_char * 129),
("description", c_char * 8000),
("steamIDOwner", c_uint64),
("timeCreated", c_uint32),
("timeUpdated", c_uint32),
("timeAddedToUserList", c_uint32),
("visibility", c_int),
("banned", c_bool),
("acceptedForUse", c_bool),
("tagsTruncated", c_bool),
("tags", c_char * 1025),
("file", c_uint64),
("previewFile", c_uint64),
("fileName", c_char * 260),
("fileSize", c_uint32),
("previewFileSize", c_uint32),
("URL", c_char * 256),
("votesUp", c_uint32),
("votesDown", c_uint32),
("score", c_float),
("numChildren", c_uint32),
]


class MicroTxnAuthorizationResponse_t(Structure):
_fields_ = [
("appId", c_uint32),
Expand Down