NAV
Unity (UniTask) Unity Unity (Legacy) Unreal Engine 5 Unreal Engine 4

GS2-Lock

GS2-SDK for Game Engine Reference

SDK for Game Engine

Models

EzMutex

Mutex
The mutex provided by GS2 is a type of re-entrant lock.

When acquiring a lock, a transaction ID is specified, and the lock can be acquired again only if the same transaction ID is specified.
Since it has a reference counter, the same number of unlock operations are required when releasing it.

Type Description
mutexId string Mutex GRN
propertyId string Property ID
transactionId string Transaction ID from which the lock was acquired

Methods

get

get

///////////////////////////////////////////////////////////////
// New Experience (Enabled UniTask)
///////////////////////////////////////////////////////////////

using Gs2.Unity.Util;
#if GS2_ENABLE_UNITASK
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
#endif

var profile = new Profile(
    clientId: "your client id",
    clientSecret: "your client secret",
    reopener: new Gs2BasicReopener()
);
await profile.InitializeAsync();
var gs2 = new Gs2.Unity.Core.Gs2Domain(profile);

// Up to this line is the initialization process.

{
    var domain = gs2.Lock.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Mutex(
        propertyId: "property-0001"
    );
    var item = await domain.ModelAsync();
}
///////////////////////////////////////////////////////////////
// New Experience
///////////////////////////////////////////////////////////////

using Gs2.Unity.Util;

var profile = new Profile(
    clientId: "your client id",
    clientSecret: "your client secret",
    reopener: new Gs2BasicReopener()
);
var future = profile.Initialize();
yield return future;
if (future.Error != null)
{
    onError.Invoke(future.Error, null);
    yield break;
}
var gs2 = new Gs2.Unity.Core.Gs2Domain(profile);

// Up to this line is the initialization process.

{
    var domain = gs2.Lock.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Mutex(
        propertyId: "property-0001"
    );
    var future = domain.Model();
    yield return future;
    var item = future.Result;
}
///////////////////////////////////////////////////////////////
// Legacy Experience
///////////////////////////////////////////////////////////////

using Gs2.Core.AsyncResult;
using Gs2.Gs2Account.Unity.Result;
using Gs2.Unity.Util;

var profile = new Profile(
    clientId: "your client id",
    clientSecret: "your client secret",
    reopener: new Gs2BasicReopener()
);

{
    AsyncResult<object> asyncResult = null;
    var current = profile.Initialize(
        r => { asyncResult = r; }
    );
    yield return current;
    if (asyncResult.Error != null)
    {
        OnError(asyncResult.Error);
        yield break;
    }
}
var gs2 = new Gs2.Unity.Client(profile);

// Up to this line is the initialization process.

{
    AsyncResult<EzGetResult> asyncResult = null;
    var current = gs2.Lock.Get(
        callback: r => { asyncResult = r; },
        session: session,
        namespaceName: "namespace-0001",
        propertyId: "property-0001"
    );

    yield return current;
    if (asyncResult.Error != null)
    {
        OnError(asyncResult.Error);
        yield break;
    }

    var result = asyncResult.Result;
    var item = result.Item;
}

const auto Profile = MakeShared<Gs2::UE5::Util::FProfile>(
    "your client id",
    "your client secret",
    Gs2::Core::Model::ERegion::ApNorthEast1,
    MakeShareable<Gs2::UE5::Util::IReOpener>(new Gs2::UE5::Util::FGs2BasicReOpener())
);

Gs2::UE5::Core::Domain::FGs2DomainPtr Gs2;
{
    const auto Future = Profile->Initialize();
    Future->StartSynchronousTask();
    if (!TestFalse(WHAT, Future->GetTask().IsError())) return false;

    Gs2 = Future->GetTask().Result();
    Future->EnsureCompletion();
}

// Up to this line is the initialization process.

{
    const auto Domain = Gs2->Lock->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Mutex(
        "property-0001" // propertyId
    );
    const auto item = Domain.Model();
}
ProfilePtr = std::make_shared<gs2::ez::Profile>(
    TCHAR_TO_ANSI(*ClientId),
    TCHAR_TO_ANSI(*ClientSecret),
    gs2::ez::Gs2BasicReopener()
);

ClientPtr = std::make_shared<gs2::ez::Client>(
    *ProfilePtr
);

ProfilePtr->initialize(
    [this](gs2::ez::Profile::AsyncInitializeResult r)
    {
        if (r.getError())
        {
            GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, "profile.initialize failed.");
        }
        else
        {
            AccountCreate();
        }
    }
);

// Up to this line is the initialization process.

ClientPtr->lock.getMutex(
    [](gs2::ez::account::AsyncEzGetMutexResult r)
    {
        if (r.getError())
        {
            GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, "lock.getMutex failed.");
        }
        else
        {
            Item = r.getResult()->getItem();
        }
    },
    ProfilePtr->getGs2Session(),
    TCHAR_TO_ANSI("namespace-0001"), // namespaceName
    TCHAR_TO_ANSI("property-0001") // propertyId
);

Obtain mutex status



Request

Type Require Default Limitation Description
namespaceName string ~ 32 chars Namespace Name
propertyId string ~ 1024 chars Property ID
accessToken string ~ 128 chars User Id

Result

Type Description
item EzMutex Mutex

lock

lock

///////////////////////////////////////////////////////////////
// New Experience (Enabled UniTask)
///////////////////////////////////////////////////////////////

using Gs2.Unity.Util;
#if GS2_ENABLE_UNITASK
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
#endif

var profile = new Profile(
    clientId: "your client id",
    clientSecret: "your client secret",
    reopener: new Gs2BasicReopener()
);
await profile.InitializeAsync();
var gs2 = new Gs2.Unity.Core.Gs2Domain(profile);

// Up to this line is the initialization process.

{
    var domain = gs2.Lock.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Mutex(
        propertyId: "property-0001"
    );
    var result = await domain.LockAsync(
        transactionId: "transaction-0001",
        ttl: 100000L
    );
    var item = await result.ModelAsync();
}
///////////////////////////////////////////////////////////////
// New Experience
///////////////////////////////////////////////////////////////

using Gs2.Unity.Util;

var profile = new Profile(
    clientId: "your client id",
    clientSecret: "your client secret",
    reopener: new Gs2BasicReopener()
);
var future = profile.Initialize();
yield return future;
if (future.Error != null)
{
    onError.Invoke(future.Error, null);
    yield break;
}
var gs2 = new Gs2.Unity.Core.Gs2Domain(profile);

// Up to this line is the initialization process.

{
    var domain = gs2.Lock.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Mutex(
        propertyId: "property-0001"
    );
    var future = domain.Lock(
        transactionId: "transaction-0001",
        ttl: 100000L
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.Model();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;
}
///////////////////////////////////////////////////////////////
// Legacy Experience
///////////////////////////////////////////////////////////////

using Gs2.Core.AsyncResult;
using Gs2.Gs2Account.Unity.Result;
using Gs2.Unity.Util;

var profile = new Profile(
    clientId: "your client id",
    clientSecret: "your client secret",
    reopener: new Gs2BasicReopener()
);

{
    AsyncResult<object> asyncResult = null;
    var current = profile.Initialize(
        r => { asyncResult = r; }
    );
    yield return current;
    if (asyncResult.Error != null)
    {
        OnError(asyncResult.Error);
        yield break;
    }
}
var gs2 = new Gs2.Unity.Client(profile);

// Up to this line is the initialization process.

{
    AsyncResult<EzLockResult> asyncResult = null;
    var current = gs2.Lock.Lock(
        callback: r => { asyncResult = r; },
        session: session,
        namespaceName: "namespace-0001",
        propertyId: "property-0001",
        transactionId: "transaction-0001",
        ttl: 100000L
    );

    yield return current;
    if (asyncResult.Error != null)
    {
        OnError(asyncResult.Error);
        yield break;
    }

    var result = asyncResult.Result;
    var item = result.Item;
}

const auto Profile = MakeShared<Gs2::UE5::Util::FProfile>(
    "your client id",
    "your client secret",
    Gs2::Core::Model::ERegion::ApNorthEast1,
    MakeShareable<Gs2::UE5::Util::IReOpener>(new Gs2::UE5::Util::FGs2BasicReOpener())
);

Gs2::UE5::Core::Domain::FGs2DomainPtr Gs2;
{
    const auto Future = Profile->Initialize();
    Future->StartSynchronousTask();
    if (!TestFalse(WHAT, Future->GetTask().IsError())) return false;

    Gs2 = Future->GetTask().Result();
    Future->EnsureCompletion();
}

// Up to this line is the initialization process.

{
    const auto Domain = Gs2->Lock->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Mutex(
        "property-0001" // propertyId
    );
    const auto Future = Domain->Lock(
        "transaction-0001",
        100000L
    );
    Future->StartSynchronousTask();
    if (!TestFalse(WHAT, Future->GetTask().IsError())) return false;

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (!TestFalse(WHAT, Future2->GetTask().IsError())) return false;
    const auto Result = Future2->GetTask().Result();
}
ProfilePtr = std::make_shared<gs2::ez::Profile>(
    TCHAR_TO_ANSI(*ClientId),
    TCHAR_TO_ANSI(*ClientSecret),
    gs2::ez::Gs2BasicReopener()
);

ClientPtr = std::make_shared<gs2::ez::Client>(
    *ProfilePtr
);

ProfilePtr->initialize(
    [this](gs2::ez::Profile::AsyncInitializeResult r)
    {
        if (r.getError())
        {
            GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, "profile.initialize failed.");
        }
        else
        {
            AccountCreate();
        }
    }
);

// Up to this line is the initialization process.

ClientPtr->lock.lock(
    [](gs2::ez::account::AsyncEzLockResult r)
    {
        if (r.getError())
        {
            GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, "lock.lock failed.");
        }
        else
        {
            Item = r.getResult()->getItem();
        }
    },
    ProfilePtr->getGs2Session(),
    TCHAR_TO_ANSI("namespace-0001"), // namespaceName
    TCHAR_TO_ANSI("property-0001"), // propertyId
    TCHAR_TO_ANSI("transaction-0001"), // transactionId
    100000L // ttl
);

Obtaining a lock

Locks the resource with the property ID for the number of seconds specified by ttl.
The transaction ID must be specified when locking.
Acquisition of a lock on the same property ID by a different transaction ID will fail.
If the lock acquisition request is from the same transaction, the reference count is increased.



Request

Type Require Default Limitation Description
namespaceName string ~ 32 chars Namespace name
propertyId string ~ 1024 chars Property ID
accessToken string ~ 128 chars User Id
transactionId string ~ 256 chars Transaction ID from which the lock was acquired
ttl long ~ 9223372036854775806 Duration of lock acquisition (seconds)

Result

Type Description
item EzMutex Mutex

unlock

unlock

///////////////////////////////////////////////////////////////
// New Experience (Enabled UniTask)
///////////////////////////////////////////////////////////////

using Gs2.Unity.Util;
#if GS2_ENABLE_UNITASK
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
#endif

var profile = new Profile(
    clientId: "your client id",
    clientSecret: "your client secret",
    reopener: new Gs2BasicReopener()
);
await profile.InitializeAsync();
var gs2 = new Gs2.Unity.Core.Gs2Domain(profile);

// Up to this line is the initialization process.

{
    var domain = gs2.Lock.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Mutex(
        propertyId: "property-0001"
    );
    var result = await domain.UnlockAsync(
        transactionId: "transaction-0001"
    );
}
///////////////////////////////////////////////////////////////
// New Experience
///////////////////////////////////////////////////////////////

using Gs2.Unity.Util;

var profile = new Profile(
    clientId: "your client id",
    clientSecret: "your client secret",
    reopener: new Gs2BasicReopener()
);
var future = profile.Initialize();
yield return future;
if (future.Error != null)
{
    onError.Invoke(future.Error, null);
    yield break;
}
var gs2 = new Gs2.Unity.Core.Gs2Domain(profile);

// Up to this line is the initialization process.

{
    var domain = gs2.Lock.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Mutex(
        propertyId: "property-0001"
    );
    var future = domain.Unlock(
        transactionId: "transaction-0001"
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
}
///////////////////////////////////////////////////////////////
// Legacy Experience
///////////////////////////////////////////////////////////////

using Gs2.Core.AsyncResult;
using Gs2.Gs2Account.Unity.Result;
using Gs2.Unity.Util;

var profile = new Profile(
    clientId: "your client id",
    clientSecret: "your client secret",
    reopener: new Gs2BasicReopener()
);

{
    AsyncResult<object> asyncResult = null;
    var current = profile.Initialize(
        r => { asyncResult = r; }
    );
    yield return current;
    if (asyncResult.Error != null)
    {
        OnError(asyncResult.Error);
        yield break;
    }
}
var gs2 = new Gs2.Unity.Client(profile);

// Up to this line is the initialization process.

{
    AsyncResult<EzUnlockResult> asyncResult = null;
    var current = gs2.Lock.Unlock(
        callback: r => { asyncResult = r; },
        session: session,
        namespaceName: "namespace-0001",
        propertyId: "property-0001",
        transactionId: "transaction-0001"
    );

    yield return current;
    if (asyncResult.Error != null)
    {
        OnError(asyncResult.Error);
        yield break;
    }

    var result = asyncResult.Result;
    var item = result.Item;
}

const auto Profile = MakeShared<Gs2::UE5::Util::FProfile>(
    "your client id",
    "your client secret",
    Gs2::Core::Model::ERegion::ApNorthEast1,
    MakeShareable<Gs2::UE5::Util::IReOpener>(new Gs2::UE5::Util::FGs2BasicReOpener())
);

Gs2::UE5::Core::Domain::FGs2DomainPtr Gs2;
{
    const auto Future = Profile->Initialize();
    Future->StartSynchronousTask();
    if (!TestFalse(WHAT, Future->GetTask().IsError())) return false;

    Gs2 = Future->GetTask().Result();
    Future->EnsureCompletion();
}

// Up to this line is the initialization process.

{
    const auto Domain = Gs2->Lock->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Mutex(
        "property-0001" // propertyId
    );
    const auto Future = Domain->Unlock(
        "transaction-0001"
    );
    Future->StartSynchronousTask();
    if (!TestFalse(WHAT, Future->GetTask().IsError())) return false;
}
ProfilePtr = std::make_shared<gs2::ez::Profile>(
    TCHAR_TO_ANSI(*ClientId),
    TCHAR_TO_ANSI(*ClientSecret),
    gs2::ez::Gs2BasicReopener()
);

ClientPtr = std::make_shared<gs2::ez::Client>(
    *ProfilePtr
);

ProfilePtr->initialize(
    [this](gs2::ez::Profile::AsyncInitializeResult r)
    {
        if (r.getError())
        {
            GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, "profile.initialize failed.");
        }
        else
        {
            AccountCreate();
        }
    }
);

// Up to this line is the initialization process.

ClientPtr->lock.unlock(
    [](gs2::ez::account::AsyncEzUnlockResult r)
    {
        if (r.getError())
        {
            GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, "lock.unlock failed.");
        }
        else
        {
            Item = r.getResult()->getItem();
        }
    },
    ProfilePtr->getGs2Session(),
    TCHAR_TO_ANSI("namespace-0001"), // namespaceName
    TCHAR_TO_ANSI("property-0001"), // propertyId
    TCHAR_TO_ANSI("transaction-0001") // transactionId
);

Releasing a lock

The lock must be released from the same transaction ID.
If the lock is re-entered when the lock is acquired, the lock is released the same number of times, and the actual release occurs when the reference count reaches zero.



Request

Type Require Default Limitation Description
namespaceName string ~ 32 chars Namespace Name
propertyId string ~ 1024 chars Property ID
accessToken string ~ 128 chars User Id
transactionId string ~ 256 chars Transaction ID from which the lock was acquired

Result

Type Description
item EzMutex Mutex