Use UGC for player presets
Overview
User Generated Content (UGC) is a service that manages in-game content that has been created by your players. UGC can be a powerful way to increase engagement, retention, and loyalty among your customers, as well as to attract new ones. There are different forms of UGC, depending on the game. The opportunities are endless, but some of these items include: customizing the game character, customizing the color of a vehicle, new aspects of a weapon, creating custom maps, and so much more.
There are a lot of games that implement deep customization to their player content. With a content customization, It can increase the player's immersion and engagement with the game world, as they can create content that reflects their personality, preferences, and style. Also, it can encourage social interaction and community building among players, especially if they can make a preset out of their content and share it with others. By allowing players to showcase their creativity and identity through their content, developers can create a loyal fan base and generate positive word-of-mouth for their game.
This article walks you through how to use the UGC service to store player-generated content, display them within the game client, and use them according to your game use case.
Prerequisites
You will need access to:
- The AccelByte Gaming Services (AGS) Admin Portal
- The AGS Unreal or Unity SDK
- The AGS UGC API documentation for reference.
Create channel to store player content
UGC service manages player content based on channels. A channel is a generic entity that is used to categorize players' content. You can use channels to group contents by region, language, build version, patch, content category, or any other cases that are needed for the game scenario. It can be hardcoded or the game could let the player manage their own channel.
Create a channel using the SDK
- Unreal Engine
- Unity
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
FString ChannelName = "YourChannelName";
ApiClient->UGC.CreateChannel(ChannelName, THandler<FAccelByteModelsUGCChannelResponse>::CreateLambda([](const FAccelByteModelsUGCChannelResponse& Result)
{
// Do something if CreateV2Channel succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if CreateV2Channel fails
}));
string channelName = "YourChannelName";
UGC ugc = AccelByteSDK.GetClientRegistry().GetApi().GetUgc();
ugc.CreateChannel(channelName, result =>
{
if (result.IsError)
{
// Do something if CreateChannel fails
Debug.Log($"Error CreateChannel, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Get channel ID
string channelId = result.Value.id;
// Do something if CreateChannel succeeds
});
publicChannelService := &ugc.PublicChannelService{
Client: factory.NewUgcClient(&repository.ConfigRepositoryImpl{}),
TokenRepository: &repository.TokenRepositoryImpl{},
}
channelName := "mychannelname"
body := ugcclientmodels.ModelsPublicChannelRequest {
Name: &channelName,
}
namespace := "mygame"
userId := "myuserid"
input := &public_channel.PublicCreateChannelParams{
Body: &body,
Namespace: namespace,
UserID: userId,
}
result, err := publicChannelService.PublicCreateChannelShort(input)
import accelbyte_py_sdk.api.ugc as ugc_service
import accelbyte_py_sdk.api.ugc.models as ugc_models
result, error = ugc_service.public_create_channel(
body=ugc_models.ModelsPublicChannelRequest()
.with_name("YourChannelName"),
)
if error:
exit(error)
String channelName = "MyChannelName";
String userId = "<user-id>";
ModelsChannelResponse response;
try {
ModelsPublicChannelRequest reqBody = ModelsPublicChannelRequest.builder()
.name(channelName)
.build();
response = publicChannelWrapper.publicCreateChannel(PublicCreateChannel.builder()
.namespace("<namespace>")
.body(reqBody)
.build());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (response == null) {
// Null response from server
} else {
// Do something if successful
}
string channelName = "MyChannelName";
string userId = "<user-id>";
var response = sdk.Ugc.PublicChannel.PublicCreateChannelOp
.Execute(new ModelsPublicChannelRequest()
{
Name = channelName
}, sdk.Namespace, userId);
if (response != null)
{
string channelId = response.Id!;
// Do something if successful
}
Get the list of the player channel using the SDK
You can use this function to list of the player channel.
- Unreal Engine
- Unity
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
FString UserId = "YourUserId";
int32 Limit = 1000;
int32 Offset = 0;
FString ChannelName = "YourChannelName";
ApiClient->UGC.GetChannels(UserId, THandler<FAccelByteModelsUGCChannelsPagingResponse>::CreateLambda([](const FAccelByteModelsUGCChannelsPagingResponse& Result)
{
// Do something if GetChannels succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if GetChannels fails
}), Limit, Offset, ChannelName);
string userId = "YourUserId";
string channelName = "YourChannelName";
int limit = 1000;
int offset = 0;
UGC ugc = AccelByteSDK.GetClientRegistry().GetApi().GetUgc();
ugc.GetChannels(userId, result =>
{
if (result.IsError)
{
// Do something if GetChannels fails
Debug.Log($"Error GetChannels, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if GetChannels succeeds
}, offset, limit, channelName);
publicChannelService := &ugc.PublicChannelService{
Client: factory.NewUgcClient(&repository.ConfigRepositoryImpl{}),
TokenRepository: &repository.TokenRepositoryImpl{},
}
namespace := "mygame"
userId := "myuserid"
limit := int64(1000)
name := "mychannelname"
offset := int64(0)
input := &public_channel.GetChannelsParams{
Namespace: namespace,
UserID: userId,
Limit: &limit,
Name: &name,
Offset: &offset,
}
result, err := publicChannelService.GetChannelsShort(input)
import accelbyte_py_sdk.api.ugc as ugc_service
result, error = ugc_service.get_channels(
user_id="********************************",
limit=1000,
name="YourChannelName",
offset=0,
)
if error:
exit(error)
final PublicChannel publicChannelWrapper = new PublicChannel(sdk);
String channelName = "MyChannelName";
String userId = "<user-id>";
ModelsPaginatedGetChannelResponse response;
try {
response = publicChannelWrapper.getChannels(GetChannels.builder()
.namespace("<namespace>")
.userId(userId)
.name(channelName)
.offset(0)
.limit(1000)
.build());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (response == null) {
// Null response from server
} else {
// Do something if successful
}
string channelName = "MyChannelName";
string userId = "<user-id>";
var response = sdk.Ugc.PublicChannel.GetChannelsOp
.SetName(channelName)
.SetOffset(0)
.SetLimit(1000)
.Execute(sdk.Namespace, userId);
if (response != null)
{
// Do something if successful
}
Store player content in UGC
If you want to save your player content in UGC service as preset, you need to create a file that contains all the customization options you have applied to your player content. This file will store the information about your player content.
To create player content in UGC service, you need to complete two steps. First, you need to request a pre-signed URL from the service that will allow you to upload your file. In this step, you can also specify the basic metadata for the player content, such as name, tags, type, and subtype. Second, you need to use the pre-signed URL to upload your file to the service.
Get a pre-signed URL using the Client SDK
Get a Pre-Signed URL using the SDK
You can use this function to set the Player content metadata and get a pre-signed URL that you can use to upload your Player content to cloud storage.
- Unreal Engine
- Unity
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
FString ChannelId = "YourChannelId";
FAccelByteModelsCreateUGCRequestV2 UGCRequest = {};
UGCRequest.ContentType = "PNG";
UGCRequest.FileExtension = "PNG";
UGCRequest.Name = "UGC Integration UE4";
UGCRequest.Type = "UGC Type";
UGCRequest.SubType = "UGC SubType";
UGCRequest.Tags = { "UGC Tag1", "UGC Tag2"};
ApiClient->UGC.CreateV2Content(ChannelId, UGCRequest, THandler<FAccelByteModelsUGCCreateUGCResponseV2>::CreateLambda([](const FAccelByteModelsUGCCreateUGCResponseV2& Result)
{
// Do something if CreateV2Content succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if CreateV2Content fails
}));
string channelId = "YourChannelId";
CreateUGCRequestV2 createRequest = new CreateUGCRequestV2
{
ContentType = "PNG",
FileExtension = "PNG",
Name = "UGC Integration Unity",
Type = "UGC Type",
Tags = new[] { "UGC Tag1", "UGC Tag2" },
CustomAttributes = new Dictionary<string, object>()
};
UGC ugc = AccelByteSDK.GetClientRegistry().GetApi().GetUgc();
ugc.CreateContentV2(channelId, createRequest, result =>
{
if (result.IsError)
{
// Do something if CreateContentV2 fails
Debug.Log($"Error CreateContentV2, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
string presignedUrl = result.Value.PayloadUrl[0].url; // you can get presigned url from the result
// Do something if CreateContentV2 succeeds
});
publicChannelService := &ugc.PublicChannelService{
Client: factory.NewUgcClient(&repository.ConfigRepositoryImpl{}),
TokenRepository: &repository.TokenRepositoryImpl{},
}
namespace := "mygame"
userId := "myuserid"
limit := int64(1000)
name := "mychannelname"
offset := int64(0)
input := &public_channel.GetChannelsParams{
Namespace: namespace,
UserID: userId,
Limit: &limit,
Name: &name,
Offset: &offset,
}
result, err := publicChannelService.GetChannelsShort(input)
import accelbyte_py_sdk.api.ugc as ugc_service
import accelbyte_py_sdk.api.ugc.models as ugc_models
result, error = ugc_service.public_create_content_v2(
body=ugc_models.ModelsContentRequestV2()
.with_content_type("PNG")
.with_file_extension("PNG")
.with_name("UGC Integration Python")
.with_type("UGC Type")
.with_sub_type("UGC Subtype")
.with_tags(["UGC Tag1", "UGC Tag2"]),
channel_id="YourChannelId",
user_id="********************************",
)
if error:
exit(error)
final PublicContentV2 publicContentV2Wrapper = new PublicContentV2(sdk);
String channelId = "<YourUGCChannelId>";
String userId = "<user-id>";
ModelsCreateContentResponseV2 response;
try {
ModelsContentRequestV2 reqBody = ModelsContentRequestV2.builder()
.contentType("application/octet-stream")
.fileExtension("bin")
.name("Custom sports body")
.type("Vehicle")
.tags(Arrays.asList("Red", "Sporty"))
.customAttributes(Collections.emptyMap())
.build();
response = publicContentV2Wrapper.publicCreateContentV2(PublicCreateContentV2.builder()
.namespace("<namespace>")
.userId(userId)
.channelId(channelId)
.body(reqBody)
.build());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (response != null && response.getPayloadURL() != null && response.getPayloadURL().get(0).getUrl() != null) {
// You can get presigned url from the result
String preSignedUrl = response.getPayloadURL().get(0).getUrl();
}
string channelId = "<YourUGCChannelId>";
string userId = "<user-id>";
var response = sdk.Ugc.PublicContentV2.PublicCreateContentV2Op
.Execute(new ModelsContentRequestV2()
{
ContentType = "application/octet-stream",
FileExtension = "bin",
Name = "Custom sports body",
Type = "Vehicle",
Tags = new List<string>() { "Red", "Sporty" },
CustomAttributes = new Dictionary<string, object>()
}, channelId, sdk.Namespace, userId);
if (response != null)
{
string preSignedUrl = response.PayloadURL![0].Url!;
}
Upload the Player content file using the SDK
You'll need a pre-signed URL for this function. See Get a pre-signed URL using the Client SDK.
- Unreal Engine
- Unity
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FString Url = "PayloadUGCUrlToUpload";
TArray<uint8> DataUpload = { 106, 35, 171, 106, 138, 197, 77, 94, 182, 18, 99, 9, 245, 110, 45, 197, 22, 35};
FAccelByteNetUtilities::UploadTo(Url, DataUpload, FHttpRequestProgressDelegate::CreateLambda([](const FHttpRequestPtr& Request, int32 BytesSent, int32 BytesReceived)
{
// Do something if UploadTo still in progress successful
}),FVoidHandler::CreateLambda([]()
{
// Do something if UploadTo succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if UploadTo fails
}));
string url = "YourPresignedUrl";
byte[] yourDataToUpload;
AccelByteNetUtilities.UploadTo(url, yourDataToUpload, result =>
{
if (result.IsError)
{
// Do something if UploadTo fails
Debug.Log($"Error UploadTo, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if UploadTo succeeds
});
presignedURL := "PayloadUGCUrlToUpload"
var requestBody bytes.Buffer
resp, errResp := utils.SimpleHTTPCall(utils.GetClient(), presignedURL, "POST", "Bearer "+*token.AccessToken, "application/octet-stream", &requestBody)
if errResp != nil {
return nil, errResp
}
respBody, errRespBody := ioutil.ReadAll(resp.Body)
if errRespBody != nil {
return nil, errRespBody
}
import requests
# data_upload = ...
url = "PayloadUGCUrlToUpload"
response = requests.post(
url=url,
data=data_upload,
headers={
"Content-Type": "application/octet-stream",
}
)
String presignedUrlToUpload = "<url>"; //from PublicCreateContentV2Op
byte[] dataToUpload = new byte[] { 10, 30, 40, 50, 60, 70, 80 };
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(presignedUrlToUpload))
.PUT(HttpRequest.BodyPublishers.ofByteArray(dataToUpload))
.header("Content-Type", "application/octet-stream")
.build();
HttpResponse<String> httpResponse;
try {
httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (httpResponse.statusCode() >= HttpURLConnection.HTTP_OK && httpResponse.statusCode() >= HttpURLConnection.HTTP_MULT_CHOICE)
{
// Do something if upload is success
}
string presignedUrlToUpload = "<url>"; //from PublicCreateContentV2Op
byte[] dataToUpload = new byte[] { 10, 30, 40, 50, 60, 70, 80 };
HttpRequestMessage request = new HttpRequestMessage();
request.Method = HttpMethod.Put;
request.RequestUri = new Uri(presignedUrlToUpload);
request.Content = new StreamContent(new MemoryStream(dataToUpload));
request.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream");
var response = DefaultHttpClient.Http.Send(request);
if (response.IsSuccessStatusCode)
{
// Do something if upload is success
}
Add screenshots to player content
One way to make your player content file more attractive and informative is to add a screenshot that shows how it looks in the game. A screenshot can capture the visual effects and details that you have created with your preset file.
Get a Pre-Signed URL for uploading the screenshot using the SDK
You can use this function to get a pre-signed URL that you can use to upload your screenshot for a specific player content.
- Unreal Engine
- Unity
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
FString ContentId = "YourContentId";
FString UserId = "UserId";
FAccelByteModelsUGCUploadScreenshotV2 Screenshot;
Screenshot.Description = "Screenshot Test Description";
Screenshot.ContentType = "png";
Screenshot.FileExtension = "png";
FAccelByteModelsUGCUploadScreenshotsRequestV2 ScreenshotsRequest = {};
ScreenshotsRequest.Screenshots = { Screenshot };
ApiClient->UGC.UploadV2ScreenshotContent(ContentId, ScreenshotsRequest, THandler<FAccelByteModelsUGCUpdateContentScreenshotResponse>::CreateLambda([](const FAccelByteModelsUGCUpdateContentScreenshotResponse& Result)
{
// Do something if UploadV2ScreenshotContent succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if UploadV2ScreenshotContent fails
}));
string contentId = "YourContentId";
ScreenshotRequest screenshotRequest = new ScreenshotRequest()
{
description = "UGC Screenshot Description",
fileExtension = UGCFileExtension.PNG
};
ScreenshotsRequest screenshotsRequest = new ScreenshotsRequest()
{
screenshots = new[] { screenshotRequest }
};
UGC ugc = AccelByteSDK.GetClientRegistry().GetApi().GetUgc();
ugc.UploadContentScreenshotV2(contentId, screenshotsRequest, result =>
{
if (result.IsError)
{
// Do something if UploadContentScreenshotV2 fails
Debug.Log($"Error UploadContentScreenshotV2, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if UploadContentScreenshotV2 succeeds
});
publicContentV2Service := &ugc.PublicContentV2Service{
Client: factory.NewUgcClient(&repository.ConfigRepositoryImpl{}),
TokenRepository: &repository.TokenRepositoryImpl{},
}
description := "UGC screenshot description"
fileExtension := "PNG"
item := ugcclientmodels.ModelsCreateScreenshotRequestItem {
Description: &description,
FileExtension: &fileExtension,
}
body := ugcclientmodels.ModelsCreateScreenshotRequest {
Screenshots: []*ugcclientmodels.ModelsCreateScreenshotRequestItem {
&item,
},
}
contentId := "mycontentid"
namespace := "mygame"
userId := "myuserid"
input := &public_content_v2.UploadContentScreenshotV2Params{
Body: &body,
ContentID: contentId,
Namespace: namespace,
UserID: userId,
}
result, err := publicContentV2Service.UploadContentScreenshotV2Short(input)
import accelbyte_py_sdk.api.ugc as ugc_service
import accelbyte_py_sdk.api.ugc.models as ugc_models
result, error = ugc_service.upload_content_screenshot_v2(
body=ugc_models.ModelsCreateScreenshotRequest()
.with_screenshots([
ugc_models.ModelsCreateScreenshotRequestItem()
.with_description("Screenshot Test Description")
.with_content_type("png")
.with_file_extension("png")
]),
content_id="YourContentId",
user_id="********************************",
)
if error:
exit(error)
String contentId = "<YourUGCContentId>";
String userId = "<user-id>";
ModelsCreateScreenshotResponse response;
try {
ModelsCreateScreenshotRequest reqBody = ModelsCreateScreenshotRequest.builder()
.screenshots(Arrays.asList(ModelsCreateScreenshotRequestItem.builder()
.description("UGC screenshot description")
.fileExtension("PNG")
.build())
).build();
response = publicContentV2Wrapper.uploadContentScreenshotV2(UploadContentScreenshotV2.builder()
.namespace("<namespace>")
.userId(userId)
.contentId(contentId)
.body(reqBody)
.build());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (response != null && response.getScreenshots() != null && response.getScreenshots().get(0).getUrl() != null) {
String preSignedUrl = response.getScreenshots().get(0).getUrl();
}
string contentId = "<YourUGCContentId>";
string userId = "<user-id>";
var response = sdk.Ugc.PublicContentV2.UploadContentScreenshotV2Op
.Execute(new ModelsCreateScreenshotRequest()
{
Screenshots = new List<ModelsCreateScreenshotRequestItem>()
{
new ModelsCreateScreenshotRequestItem()
{
Description = "UGC screenshot description",
FileExtension = "PNG"
}
}
}, contentId, sdk.Namespace, userId);
if (response != null)
{
string preSignedUrl = response.Screenshots![0].Url!;
}
Upload the screenshot using the SDK
To upload screenshot for a specific player content to cloud storage, use this function:
You'll need a pre-signed URL for this function. See Get a pre-signed URL using the Client SDK.
- Unreal Engine
- Unity
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FString Url = "PayloadScreenshotUrlToUpload";
TArray<uint8> DataUpload = { 35, 171, 106, 138, 197, 77, 94, 182, 18, 99, 9, 245, 110, 45, 197, 35};
FAccelByteNetUtilities::UploadTo(Url, DataUpload, FHttpRequestProgressDelegate::CreateLambda([](const FHttpRequestPtr& Request, int32 BytesSent, int32 BytesReceived)
{
// Do something if UploadTo still in progress successful
}),FVoidHandler::CreateLambda([]()
{
// Do something if UploadTo succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if UploadTo fails
}));
string url = "YourPresignedUrl";
byte[] yourDataToUpload;
AccelByteNetUtilities.UploadTo(url, yourDataToUpload, result =>
{
if (result.IsError)
{
// Do something if UploadTo fails
Debug.Log($"Error UploadTo, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if UploadTo succeeds
});
presignedURL := "PayloadScreenshotUrlToUpload"
var requestBody bytes.Buffer
resp, errResp := utils.SimpleHTTPCall(utils.GetClient(), presignedURL, "POST", "Bearer "+*token.AccessToken, "application/octet-stream", &requestBody)
if errResp != nil {
return nil, errResp
}
respBody, errRespBody := ioutil.ReadAll(resp.Body)
if errRespBody != nil {
return nil, errRespBody
}
import requests
# data_upload = ...
url = "PayloadScreenshotUrlToUpload"
response = requests.post(
url=url,
data=data_upload,
headers={
"Content-Type": "application/octet-stream",
}
)
String presignedUrlToUpload = "<url>"; //from UploadContentScreenshotV2Op
byte[] dataToUpload = new byte[] { 35, 171, 106, 138, 197, 77, 94, 182, 18, 99, 9, 245, 110, 45, 197, 35 };
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(presignedUrlToUpload))
.PUT(HttpRequest.BodyPublishers.ofByteArray(dataToUpload))
.header("Content-Type", "application/octet-stream")
.build();
HttpResponse<String> httpResponse;
try {
httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (httpResponse.statusCode() >= HttpURLConnection.HTTP_OK && httpResponse.statusCode() >= HttpURLConnection.HTTP_MULT_CHOICE)
{
// Do something if upload is success
}
string presignedUrlToUpload = "<url>"; //from UploadContentScreenshotV2Op
byte[] dataToUpload = new byte[] { 35, 171, 106, 138, 197, 77, 94, 182, 18, 99, 9, 245, 110, 45, 197, 35 };
HttpRequestMessage request = new HttpRequestMessage();
request.Method = HttpMethod.Put;
request.RequestUri = new Uri(presignedUrlToUpload);
request.Content = new StreamContent(new MemoryStream(dataToUpload));
request.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream");
var response = DefaultHttpClient.Http.Send(request);
if (response.IsSuccessStatusCode)
{
// Do something if upload is success
}
Display player content by share code
When a player creates a player content, UGC service will generate a unique share code for it. The player can share the share code with other players to show off their creation or invite them to try it out. Other players can use the share code to access the details of the preset. They can also apply the preset to their own game or modify it as they wish.
Displaying the Player content by the share code using SDK
This example below shows you how to retrieve the player content using the sharecode.
- Unreal Engine
- Unity
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
FString ShareCode = "YourUGCShareCode";
ApiClient->UGC.GetV2ContentByShareCode(ShareCode, THandler<FAccelByteModelsUGCContentResponseV2>::CreateLambda([](const FAccelByteModelsUGCContentResponseV2& Result)
{
// Do something if GetV2ContentByShareCode succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if GetV2ContentByShareCode fails
}));
string shareCode = "YourUGCShareCode";
UGC ugc = AccelByteSDK.GetClientRegistry().GetApi().GetUgc();
ugc.GetContentByShareCodeV2(shareCode, result =>
{
if (result.IsError)
{
// Do something if GetContentByShareCodeV2 fails
Debug.Log($"Error GetContentByShareCodeV2, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if GetContentByShareCodeV2 succeeds
});
publicContentV2Service := &ugc.PublicContentV2Service{
Client: factory.NewUgcClient(&repository.ConfigRepositoryImpl{}),
TokenRepository: &repository.TokenRepositoryImpl{},
}
namespace := "mygame"
shareCode := "mysharecode"
input := &public_content_v2.PublicGetContentByShareCodeV2Params{
Namespace: namespace,
ShareCode: shareCode,
}
result, err := publicContentV2Service.PublicGetContentByShareCodeV2Short(input)
import accelbyte_py_sdk.api.ugc as ugc_service
result, error = ugc_service.public_get_content_by_share_code_v2(
share_code="YourUGCShareCode",
)
if error:
exit(error)
final PublicContentV2 publicContentV2Wrapper = new PublicContentV2(sdk);
String shareCode = "<YourUGCShareCode>";
ModelsContentDownloadResponseV2 response;
try {
response = publicContentV2Wrapper.publicGetContentByShareCodeV2(PublicGetContentByShareCodeV2.builder()
.namespace("<namespace>")
.shareCode(shareCode)
.build());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (response == null) {
// Null response from server
} else {
// Do something if successful
}
string shareCode = "<YourUGCShareCode>";
var response = sdk.Ugc.PublicContentV2.PublicGetContentByShareCodeV2Op
.Execute(sdk.Namespace, shareCode);
if (response != null)
{
// Do something if successful
}
Modify the player content
When modifying the Player content, player could update only the Player content metadata, or the preset file.
To modify the preset file in UGC service, you need to complete three steps. First, you need to request a pre-signed URL from the service that will allow you to upload your new file. Second, you need to use the pre-signed URL to upload your file to the service. Third, you need to commit the changes by updating the new file location.
Update the Player content metadata using the SDK
To update the player content metadata, use this function:
- Unreal Engine
- Unity
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
FString ChannelId = "YourChannelId";
FString ContentId = "YourContentId";
FAccelByteModelsModifyUGCRequestV2 ModifyRequest = {};
ModifyRequest.Name = "Updated UGC Integration UE4";
ModifyRequest.Type = "Updated UGC Type";
ModifyRequest.SubType = "Updated UGC SubType";
ModifyRequest.Tags = { "Updated UGC Tag1", "Updated UGC Tag2"};
ApiClient->UGC.ModifyV2Content(ChannelId, ContentId, ModifyRequest, THandler<FAccelByteModelsUGCModifyUGCResponseV2>::CreateLambda([](const FAccelByteModelsUGCModifyUGCResponseV2& Result)
{
// Do something if ModifyV2Content succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if ModifyV2Content fails
}));
string channelId = "YourChannelId";
string contentId = "YourContentId";
ModifyUGCRequestV2 ModifyRequest = new ModifyUGCRequestV2
{
Name = "Updated UGC Integration Unity",
Type = "Updated UGC Type",
Tags = new[] { "Updated UGC Tag1", "Updated UGC Tag2" },
CustomAttributes = new Dictionary<string, object>()
};
UGC ugc = AccelByteSDK.GetClientRegistry().GetApi().GetUgc();
ugc.ModifyContentV2(channelId, contentId, ModifyRequest, result =>
{
if (result.IsError)
{
// Do something if ModifyContentV2 fails
Debug.Log($"Error ModifyContentV2, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if ModifyContentV2 succeeds
});
publicContentV2Service := &ugc.PublicContentV2Service{
Client: factory.NewUgcClient(&repository.ConfigRepositoryImpl{}),
TokenRepository: &repository.TokenRepositoryImpl{},
}
body := ugcclientmodels.ModelsUpdateContentRequestV2 {
Name: "Custom sports body",
Type: "Vehicle",
SubType: "Body",
Tags: []string{"Blue","Body","Sporty"},
CustomAttributes: map[string]interface{}{},
}
channelId := "mychannelid"
contentId := "mycontentid"
namespace := "mygame"
userId := "myuserid"
input := &public_content_v2.PublicUpdateContentV2Params{
Body: &body,
ChannelID: channelId,
ContentID: contentId,
Namespace: namespace,
UserID: userId,
}
result, err := publicContentV2Service.PublicUpdateContentV2Short(input)
import accelbyte_py_sdk.api.ugc as ugc_service
import accelbyte_py_sdk.api.ugc.models as ugc_models
result, error = ugc_service.public_update_content_v2(
body=ugc_models.ModelsUpdateContentRequestV2()
.with_name("Updated UGC Integration Python")
.with_type("Updated UGC Type")
.with_sub_type("Updated UGC Subtype")
.with_tags(["Updated UGC Tag1", "Updated UGC Tag2"]),
channel_id="YourChannelId",
content_id="YourContentId",
user_id="********************************",
)
if error:
exit(error)
final PublicContentV2 publicContentV2Wrapper = new PublicContentV2(sdk);
String channelId = "<YourUGCChannelId>";
String contentId = "<YourUGCContentId>";
String userId = "<user-id>";
ModelsUpdateContentResponseV2 response;
try {
ModelsUpdateContentRequestV2 reqBody = ModelsUpdateContentRequestV2.builder()
.name("Custom sports body")
.type("Vehicle")
.subType("Body")
.tags(Arrays.asList("Blue", "Body", "Sporty"))
.customAttributes(Collections.emptyMap())
.build();
response = publicContentV2Wrapper.publicUpdateContentV2(PublicUpdateContentV2.builder()
.namespace("<namespace>")
.userId(userId)
.channelId(channelId)
.contentId(contentId)
.body(reqBody)
.build());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (response == null) {
// Null response from server
} else {
// Do something if successful
}
string channelId = "<YourUGCChannelId>";
string contentId = "<YourUGCContentId>";
string userId = "<user-id>";
var response = sdk.Ugc.PublicContentV2.PublicUpdateContentV2Op
.Execute(new ModelsUpdateContentRequestV2()
{
Name = "Custom sports body",
Type = "Vehicle",
SubType = "Body",
Tags = new List<string>() { "Blue", "Body", "Sporty" },
CustomAttributes = new Dictionary<string, object>()
}, channelId, contentId, sdk.Namespace, userId);
if (response != null)
{
// Do something if successful
}
Request a Pre-Signed URL using the SDK
To get a pre-signed URL that you can use to upload your updated player content to cloud storage, use this function:
- Unreal Engine
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
FString ChannelId = "YourChannelId";
FString ContentId = "YourContentId";
FAccelByteModelsUploadContentURLRequestV2 UploadRequest = {};
UploadRequest.ContentType = "PNG";
UploadRequest.FileExtension = "PNG";
ApiClient->UGC.GenerateUploadContentURLV2(ChannelId, ContentId, UploadRequest, THandler<FAccelByteModelsUGCUploadContentURLResponseV2>::CreateLambda([](const FAccelByteModelsUGCUploadContentURLResponseV2& Result)
{
// Do something if GenerateUploadContentURLV2 succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if GenerateUploadContentURLV2 fails
}));
publicContentV2Service := &ugc.PublicContentV2Service{
Client: factory.NewUgcClient(&repository.ConfigRepositoryImpl{}),
TokenRepository: &repository.TokenRepositoryImpl{},
}
body := ugcclientmodels.ModelsGenerateContentUploadURLRequest {
ContentType: "PNG",
FileExtension: "PNG",
}
channelId := "mychannelid"
contentId := "mycontentid"
namespace := "mygame"
userId := "myuserid"
input := &public_content_v2.PublicGenerateContentUploadURLV2Params{
Body: &body,
ChannelID: channelId,
ContentID: contentId,
Namespace: namespace,
UserID: userId,
}
result, err := publicContentV2Service.PublicGenerateContentUploadURLV2Short(input)
import accelbyte_py_sdk.api.ugc as ugc_service
import accelbyte_py_sdk.api.ugc.models as ugc_models
result, error = ugc_service.public_generate_content_upload_urlv2(
body=ugc_models.ModelsGenerateContentUploadURLRequest()
.with_content_type("PNG")
.with_file_extension("PNG"),
channel_id="YourChannelId",
content_id="YourContentId",
user_id="********************************",
)
if error:
exit(error)
final PublicContentV2 publicContentV2Wrapper = new PublicContentV2(sdk);
String channelId = "<YourUGCChannelId>";
String contentId = "<YourUGCContentId>";
String userId = "<user-id>";
ModelsGenerateContentUploadURLResponse response;
try {
ModelsGenerateContentUploadURLRequest reqBody = ModelsGenerateContentUploadURLRequest.builder()
.contentType("PNG")
.fileExtension("PNG")
.build();
response = publicContentV2Wrapper.publicGenerateContentUploadURLV2(PublicGenerateContentUploadURLV2.builder()
.namespace("<namespace>")
.userId(userId)
.channelId(channelId)
.contentId(contentId)
.body(reqBody)
.build());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (response != null && response.getUrl() != null)
{
String preSignedUrl = response.getUrl();
}
string channelId = "<YourUGCChannelId>";
string contentId = "<YourUGCContentId>";
string userId = "<user-id>";
var response = sdk.Ugc.PublicContentV2.PublicGenerateContentUploadURLV2Op
.Execute(new ModelsGenerateContentUploadURLRequest()
{
ContentType = "PNG",
FileExtension = "PNG"
}, channelId, contentId, sdk.Namespace, userId);
if (response != null)
{
string preSignedUrl = response.Url!;
}
Upload the updated Player content file using the SDK
You'll need a pre-signed URL for this function. See Get a pre-signed URL using the Client SDK.
- Unreal Engine
- Unity
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FString Url = "PayloadUpdatedUGCUrlToUpload";
TArray<uint8> DataUpload = { 106, 35, 171, 106, 138, 197, 94, 182, 18, 99, 9, 245, 110, 45, 197, 35};
FAccelByteNetUtilities::UploadTo(Url, DataUpload, FHttpRequestProgressDelegate::CreateLambda([](const FHttpRequestPtr& Request, int32 BytesSent, int32 BytesReceived)
{
// Do something if UploadTo still in progress successful
}),FVoidHandler::CreateLambda([]()
{
// Do something if UploadTo succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if UploadTo fails
}));
string url = "YourPresignedUrl";
byte[] yourDataToUpload;
AccelByteNetUtilities.UploadTo(url, yourDataToUpload, result =>
{
if (result.IsError)
{
// Do something if UploadTo fails
Debug.Log($"Error UploadTo, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if UploadTo succeeds
});
presignedURL := "PayloadUpdatedUGCUrlToUpload"
var requestBody bytes.Buffer
resp, errResp := utils.SimpleHTTPCall(utils.GetClient(), presignedURL, "PUT", "Bearer "+*token.AccessToken, "application/octet-stream", &requestBody)
if errResp != nil {
return nil, errResp
}
respBody, errRespBody := ioutil.ReadAll(resp.Body)
if errRespBody != nil {
return nil, errRespBody
}
import requests
# data_upload = ...
url = "PayloadUpdatedUGCUrlToUpload"
response = requests.post(
url=url,
data=data_upload,
headers={
"Content-Type": "application/octet-stream",
}
)
String presignedUrlToUpload = "<url>"; //from PublicGenerateContentUploadURLV2Op
byte[] dataToUpload = new byte[] { 106, 35, 171, 106, 138, 197, 94, 182, 18, 99, 9, 245, 110, 45, 197, 35 };
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(presignedUrlToUpload))
.PUT(HttpRequest.BodyPublishers.ofByteArray(dataToUpload))
.header("Content-Type", "application/octet-stream")
.build();
HttpResponse<String> httpResponse;
try {
httpResponse = client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (httpResponse.statusCode() >= HttpURLConnection.HTTP_OK && httpResponse.statusCode() >= HttpURLConnection.HTTP_MULT_CHOICE)
{
// Do something if upload is success
}
string presignedUrlToUpload = "<url>"; //from PublicGenerateContentUploadURLV2Op
byte[] dataToUpload = new byte[] { 106, 35, 171, 106, 138, 197, 94, 182, 18, 99, 9, 245, 110, 45, 197, 35 };
HttpRequestMessage request = new HttpRequestMessage();
request.Method = HttpMethod.Put;
request.RequestUri = new Uri(presignedUrlToUpload);
request.Content = new StreamContent(new MemoryStream(dataToUpload));
request.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream");
var response = DefaultHttpClient.Http.Send(request);
if (response.IsSuccessStatusCode)
{
// Do something if upload is success
}
Update the Player content file location using the SDK
Once the player content file is uploaded, commit the changes to make sure the new file location is updated by using the following function:
- Unreal Engine
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
FString ChannelId = "YourChannelId";
FString ContentId = "YourContentId";
FString FileExtension = "PNG";
FString S3Key = "YourContentS3Key";
ApiClient->UGC.UpdateContentFileLocationV2(ChannelId, ContentId, FileExtension, S3Key, THandler<FAccelByteModelsUGCUpdateContentFileLocationResponseV2>::CreateLambda([](const FAccelByteModelsUGCUpdateContentFileLocationResponseV2& Response)
{
// Do something if UpdateContentFileLocationV2 succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if UpdateContentFileLocationV2 fails
}));
publicContentV2Service := &ugc.PublicContentV2Service{
Client: factory.NewUgcClient(&repository.ConfigRepositoryImpl{}),
TokenRepository: &repository.TokenRepositoryImpl{},
}
fileLocation := "mycontents3key"
body := ugcclientmodels.ModelsUpdateFileLocationRequest {
FileExtension: "PNG",
FileLocation: &fileLocation,
}
channelId := "mychannelid"
contentId := "mycontentid"
namespace := "mygame"
userId := "myuserid"
input := &public_content_v2.PublicUpdateContentFileLocationParams{
Body: &body,
ChannelID: channelId,
ContentID: contentId,
Namespace: namespace,
UserID: userId,
}
result, err := publicContentV2Service.PublicUpdateContentFileLocationShort(input)
import accelbyte_py_sdk.api.ugc as ugc_service
import accelbyte_py_sdk.api.ugc.models as ugc_models
result, error = ugc_service.public_update_content_file_location(
body=ugc_models.ModelsUpdateFileLocationRequest()
.with_file_location("YourContentS3Key")
.with_file_extension("PNG"),
channel_id="YourChannelId",
content_id="YourContentId",
user_id="********************************",
)
if error:
exit(error)
final PublicContentV2 publicContentV2Wrapper = new PublicContentV2(sdk);
String channelId = "<YourUGCChannelId>";
String contentId = "<YourUGCContentId>";
String userId = "<user-id>";
ModelsUpdateContentResponseV2 response;
try {
ModelsUpdateFileLocationRequest reqBody = ModelsUpdateFileLocationRequest.builder()
.fileExtension("PNG")
.fileLocation("<YourContentS3Key>")
.build();
response = publicContentV2Wrapper.publicUpdateContentFileLocation(PublicUpdateContentFileLocation.builder()
.namespace("<namespace>")
.userId(userId)
.channelId(channelId)
.contentId(contentId)
.body(reqBody)
.build());
} catch (Exception e) {
// Do something if an error occurs
return;
}
if (response == null) {
// Null response from server
} else {
// Do something if successful
}
string channelId = "<YourUGCChannelId>";
string contentId = "<YourUGCContentId>";
string userId = "<user-id>";
var response = sdk.Ugc.PublicContentV2.PublicUpdateContentFileLocationOp
.Execute(new ModelsUpdateFileLocationRequest()
{
FileExtension = "PNG",
FileLocation = "<YourContentS3Key>"
}, channelId, contentId, sdk.Namespace, userId);
if (response != null)
{
// Do something if successful
}
Delete player content
Delete player content using the Client SDK
- Unreal Engine
- Unity
- Go Extend SDK
- Python Extend SDK
- Java Extend SDK
- C# Extend SDK
FApiClientPtr ApiClient = FMultiRegistry::GetApiClient();
FString ChannelId = "YourChannelId";
FString ContentId = "YourContentId";
ApiClient->UGC.DeleteV2Content(ChannelId, ContentId, FVoidHandler::CreateLambda([]()
{
// Do something if DeleteV2Content succeeds
}), FErrorHandler::CreateLambda([](int32 ErrorCode, const FString& ErrorMessage)
{
// Do something if DeleteV2Content fails
}));
string channelId = "YourChannelId";
string contentId = "YourContentId";
UGC ugc = AccelByteSDK.GetClientRegistry().GetApi().GetUgc();
ugc.DeleteContentV2(channelId, contentId, result =>
{
if (result.IsError)
{
// Do something if DeleteContentV2 fails
Debug.Log($"Error DeleteContentV2, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if DeleteContentV2 succeeds
});
publicContentV2Service := &ugc.PublicContentV2Service{
Client: factory.NewUgcClient(&repository.ConfigRepositoryImpl{}),
TokenRepository: &repository.TokenRepositoryImpl{},
}
channelId := "mychannelid"
contentId := "mycontentid"
namespace := "mygame"
userId := "myuserid"
input := &public_content_v2.PublicDeleteContentV2Params{
ChannelID: channelId,
ContentID: contentId,
Namespace: namespace,
UserID: userId,
}
err := publicContentV2Service.PublicDeleteContentV2Short(input)
import accelbyte_py_sdk.api.ugc as ugc_service
result, error = ugc_service.public_delete_content_v2(
channel_id="YourChannelId",
content_id="YourContentId",
user_id="********************************",
)
if error:
exit(error)
final PublicContentV2 publicContentV2Wrapper = new PublicContentV2(sdk);
String channelId = "<YourUGCChannelId>";
String contentId = "<YourUGCContentId>";
String userId = "<user-id>";
try {
publicContentV2Wrapper.publicDeleteContentV2(PublicDeleteContentV2.builder()
.namespace("<namespace>")
.userId(userId)
.channelId(channelId)
.contentId(contentId)
.build());
} catch (Exception e) {
// Do something if an error occurs
return;
}
string channelId = "<YourUGCChannelId>";
string contentId = "<YourUGCContentId>";
string userId = "<user-id>";
sdk.Ugc.PublicContentV2.PublicDeleteContentV2Op
.Execute(channelId, contentId, sdk.Namespace, userId);