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
72 changes: 72 additions & 0 deletions .github/workflows/upm-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: UPM Release

on:
workflow_call:
inputs:
version:
required: true
type: string

jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'

- name: Restore
run: dotnet restore Gamism.SDK/Gamism.SDK.Core/Gamism.SDK.Core.csproj

- name: Build Core (Release)
run: dotnet build Gamism.SDK/Gamism.SDK.Core/Gamism.SDK.Core.csproj -c Release --no-restore

- name: Update DLL in Unity package
run: |
cp Gamism.SDK/Gamism.SDK.Core/bin/Release/netstandard2.0/Gamism.SDK.Core.dll \
Gamism.SDK/Gamism.SDK.Unity/Runtime/Plugins/Gamism.SDK.Core.dll

- name: Update package.json version
run: |
jq '.version = "${{ inputs.version }}"' \
Gamism.SDK/Gamism.SDK.Unity/package.json > /tmp/package.json
mv /tmp/package.json Gamism.SDK/Gamism.SDK.Unity/package.json

- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

- name: Commit release artifacts
run: |
git add Gamism.SDK/Gamism.SDK.Unity/Runtime/Plugins/Gamism.SDK.Core.dll
git add Gamism.SDK/Gamism.SDK.Unity/package.json
git diff --cached --quiet || git commit -m "ci: release v${{ inputs.version }} [skip ci]"

- name: Split upm subtree
run: |
git subtree split \
--prefix=Gamism.SDK/Gamism.SDK.Unity \
--branch upm-publish

- name: Push to upm branch
run: git push origin upm-publish:upm --force

- name: Tag upm version
run: |
TAG="upm/v${{ inputs.version }}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Tag $TAG already exists. Skipping."
exit 0
fi
git tag "$TAG" upm-publish
git push origin "$TAG"
30 changes: 29 additions & 1 deletion .github/workflows/versioning.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
outputs:
version: ${{ steps.bump.outputs.version }}
is_new: ${{ steps.bump.outputs.is_new }}
unity_changed: ${{ steps.unity_changes.outputs.changed }}

steps:
- name: Checkout
Expand Down Expand Up @@ -64,6 +65,24 @@ jobs:
echo "is_new=true" >> $GITHUB_OUTPUT
echo "New version: $VERSION"

- name: Check Unity SDK changes
id: unity_changes
run: |
git fetch --tags
TAG=$(git tag -l 'v*.*.*' --sort=-v:refname | head -n 1)

if [ -z "$TAG" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
exit 0
fi

CHANGES=$(git diff --name-only "$TAG"..HEAD -- Gamism.SDK/Gamism.SDK.Unity/)
if [ -n "$CHANGES" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
else
echo "changed=false" >> $GITHUB_OUTPUT
fi

- name: Create tag
if: steps.bump.outputs.is_new == 'true'
run: |
Expand All @@ -89,4 +108,13 @@ jobs:
permissions:
contents: write
packages: write
secrets: inherit
secrets: inherit

upm-release:
needs: versioning
if: needs.versioning.outputs.is_new == 'true' && needs.versioning.outputs.unity_changed == 'true'
uses: ./.github/workflows/upm-release.yml
with:
version: ${{ needs.versioning.outputs.version }}
permissions:
contents: write
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ public class CommonApiResponseOperationFilter : IOperationFilter
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var returnType = UnwrapType(context.MethodInfo.ReturnType);
var hideDataField = typeof(ICommonApiResponse).IsAssignableFrom(returnType);
var hideDataField = !returnType.IsGenericType
|| returnType.GetGenericTypeDefinition() != typeof(CommonApiResponse<>)
|| returnType.GetGenericArguments()[0] == typeof(EmptyResponse);

if (!operation.Responses.TryGetValue("200", out var response))
return;
Expand Down
10 changes: 5 additions & 5 deletions Gamism.SDK/Gamism.SDK.Unity/Runtime/Gamism.SDK.Unity.asmdef
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"name": "Gamism.SDK.Unity",
"rootNamespace": "Gamism.SDK.Unity",
"references": [
"Gamism.SDK.Core"
],
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"overrideReferences": true,
"precompiledReferences": [
"Gamism.SDK.Core.dll"
],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
Expand Down
20 changes: 20 additions & 0 deletions Gamism.SDK/Gamism.SDK.Unity/Runtime/Network/ApiManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,54 @@

namespace Gamism.SDK.Unity.Network
{
/// <summary>
/// Gamism 서버와 통신하는 HTTP 클라이언트 싱글톤.
/// 모든 응답은 <see cref="CommonApiResponse{T}"/>로 반환되며,
/// 네트워크 오류도 예외 대신 <see cref="CommonApiResponse.Error{T}"/>로 반환됩니다.
/// </summary>
public class ApiManager : MonoSingleton<ApiManager>
{
/// <summary>모든 요청에 붙는 기본 URL (예: "https://api.example.com").</summary>
public string BaseUrl { get; set; } = string.Empty;

/// <summary>요청 타임아웃 (초). 기본값 30초.</summary>
public float Timeout { get; set; } = 30f;

/// <summary>JSON 직렬화기. 기본값은 <see cref="NewtonsoftJsonSerializer"/>.</summary>
public IJsonSerializer Serializer { get; set; } = new NewtonsoftJsonSerializer();

private readonly Dictionary<string, string> _defaultHeaders = new Dictionary<string, string>();

/// <summary>모든 요청에 공통으로 포함할 헤더를 설정합니다 (예: Authorization).</summary>
public void SetDefaultHeader(string key, string value) => _defaultHeaders[key] = value;

/// <summary>설정된 기본 헤더를 제거합니다.</summary>
public void RemoveDefaultHeader(string key) => _defaultHeaders.Remove(key);

/// <summary>GET 요청을 보냅니다.</summary>
/// <param name="path">BaseUrl 이후의 경로 (예: "/users/1").</param>
/// <param name="callback">응답 콜백. 실패 시에도 반드시 호출됩니다.</param>
public Coroutine Get<T>(string path, Action<CommonApiResponse<T>> callback)
{
var request = UnityWebRequest.Get(BaseUrl + path);
return StartCoroutine(Send(request, callback));
}

/// <summary>POST 요청을 보냅니다. body는 JSON으로 직렬화됩니다.</summary>
public Coroutine Post<T>(string path, object body, Action<CommonApiResponse<T>> callback)
{
var request = BuildBodyRequest("POST", path, body);
return StartCoroutine(Send(request, callback));
}

/// <summary>PUT 요청을 보냅니다. body는 JSON으로 직렬화됩니다.</summary>
public Coroutine Put<T>(string path, object body, Action<CommonApiResponse<T>> callback)
{
var request = BuildBodyRequest("PUT", path, body);
return StartCoroutine(Send(request, callback));
}

/// <summary>DELETE 요청을 보냅니다.</summary>
public Coroutine Delete<T>(string path, Action<CommonApiResponse<T>> callback)
{
var request = UnityWebRequest.Delete(BaseUrl + path);
Expand Down Expand Up @@ -87,6 +106,7 @@ private IEnumerator Send<T>(UnityWebRequest request, Action<CommonApiResponse<T>
}
catch (Exception e)
{
// 역직렬화 실패도 예외 대신 Error 응답으로 반환
callback?.Invoke(CommonApiResponse.Error<T>($"Deserialize failed: {e.Message}", (HttpStatusCode)statusCode));
}
}
Expand Down
8 changes: 8 additions & 0 deletions Gamism.SDK/Gamism.SDK.Unity/Runtime/Plugins.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.