Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9cd6708743 | |||
| c6505fede9 | |||
| ab525cc22e | |||
| f0ea613a26 | |||
| 3e348a68b9 | |||
| e2069a938e | |||
| 1337717e14 | |||
| ede4078835 | |||
| 156d0e2eec | |||
| 611133776a | |||
| a8a27dfd07 | |||
| 74760e087b | |||
| ba25af4f56 | |||
| 7ba32716f6 | |||
| a8a7cbb210 | |||
| 09149c9e83 | |||
| d11e496495 | |||
| 57b8e7c73e | |||
| 2622112562 | |||
| fb7830bf75 | |||
| 33a47f48c1 | |||
| 2fbab9a7b7 | |||
| 3a95cf6c29 | |||
| a296ff2615 | |||
| 9fb87079a3 | |||
| 5c82fff5ed | |||
| fd96271bbe | |||
| 1694747bf7 | |||
| 12d127ad96 | |||
| 0ed53c72c7 | |||
| d4e41c9747 | |||
| 7f774e88c2 | |||
| 0a6b927023 | |||
| c8f071c350 | |||
| cad9d76612 | |||
| e0e191dc6b | |||
| 7870cf623e | |||
| ac4862a6b3 | |||
| 1443ddda68 | |||
| 1e0990fe6a | |||
| f765becf06 | |||
| 9acc18e1fa | |||
| 7125bbc537 | |||
| 1f893c30bb | |||
| 2ba101f261 | |||
| 45671889c3 | |||
| 28be9bc539 | |||
| da1028388a | |||
| 7c4909b485 | |||
| 4523bf0d79 | |||
| 5c9c75e5ea | |||
| e6b57bb346 | |||
| eabfbae92d |
@@ -1,30 +0,0 @@
|
||||
name: Publish to Gitea Packages
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: 'Version tag (e.g., 1.0.0)'
|
||||
required: true
|
||||
type: string
|
||||
run-name: "Publish version v${{ inputs.tag_name }} to Gitea Packages"
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
project:
|
||||
- OmegaLeo.HelperLib
|
||||
- OmegaLeo.HelperLib.Changelog
|
||||
- OmegaLeo.HelperLib.Game
|
||||
- OmegaLeo.HelperLib.Documentation
|
||||
- OmegaLeo.HelperLib.Shared
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./${{ matrix.project }}/${{ matrix.project }}.csproj" -c Release /p:Version=${{ inputs.tag_name }}
|
||||
- name: Publish to Gitea Packages
|
||||
run: dotnet nuget push ./${{ matrix.project }}/bin/Release/${{ matrix.project }}.${{ inputs.tag_name }}.nupkg --api-key ${{ secrets.TOKEN }} --source ${{ github.server_url }}/api/packages/${{ github.repository_owner }}/nuget/index.json --skip-duplicate
|
||||
@@ -1,37 +0,0 @@
|
||||
name: Publish Nuget Packages
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
run-name: "Publish version v${{ github.event.release.tag_name }} to nuget"
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
project:
|
||||
- OmegaLeo.HelperLib
|
||||
- OmegaLeo.HelperLib.Changelog
|
||||
- OmegaLeo.HelperLib.Game
|
||||
- OmegaLeo.HelperLib.Documentation
|
||||
- OmegaLeo.HelperLib.Shared
|
||||
env:
|
||||
VERSION: ${{ github.event.release.tag_name }}
|
||||
PACKAGE: ./${{ matrix.project }}/bin/Release/${{ matrix.project }}.${{ github.event.release.tag_name }}.nupkg
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./${{ matrix.project }}/${{ matrix.project }}.csproj" -c Release /p:Version=$VERSION /p:PackageReleaseNotes="See ${{ github.server_url }}/${{ github.repository }}/releases/tag/$VERSION"
|
||||
- name: Publish Nuget Package
|
||||
run: dotnet nuget push "$PACKAGE" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
- name: Publish to Gitea Packages
|
||||
run: dotnet nuget push "$PACKAGE" --api-key ${{ secrets.TOKEN }} --source ${{ github.server_url }}/api/packages/${{ github.repository_owner }}/nuget/index.json --skip-duplicate
|
||||
- name: Upload assets to release
|
||||
run: |
|
||||
curl --fail --silent --show-error \
|
||||
-H "Authorization: token ${{ secrets.TOKEN }}" \
|
||||
-F "attachment=@$PACKAGE" \
|
||||
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/${{ github.event.release.id }}/assets?name=${{ matrix.project }}.$VERSION.nupkg"
|
||||
@@ -1,5 +1,5 @@
|
||||
# This workflow will build a .NET project
|
||||
# Runs on Gitea Actions (GitHub Actions compatible syntax): https://docs.gitea.com/usage/actions/overview
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
|
||||
|
||||
name: .NET
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
name: Publish to GitHub Packages
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: 'Version tag (e.g., 1.0.0)'
|
||||
required: true
|
||||
type: string
|
||||
run-name: "Publish version v${{ inputs.tag_name }} to GitHub Packages"
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
jobs:
|
||||
publish-helper-lib:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./OmegaLeo.HelperLib/OmegaLeo.HelperLib.csproj" -c Release /p:Version=${{ inputs.tag_name }}
|
||||
- name: Publish to GitHub Packages
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib/bin/Release/OmegaLeo.HelperLib.${{ inputs.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
|
||||
|
||||
publish-changelog-lib:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./OmegaLeo.HelperLib.Changelog/OmegaLeo.HelperLib.Changelog.csproj" -c Release /p:Version=${{ inputs.tag_name }}
|
||||
- name: Publish to GitHub Packages
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Changelog/bin/Release/OmegaLeo.HelperLib.Changelog.${{ inputs.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
|
||||
|
||||
publish-game-lib:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./OmegaLeo.HelperLib.Game/OmegaLeo.HelperLib.Game.csproj" -c Release /p:Version=${{ inputs.tag_name }}
|
||||
- name: Publish to GitHub Packages
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Game/bin/Release/OmegaLeo.HelperLib.Game.${{ inputs.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
|
||||
|
||||
publish-doc-lib:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./OmegaLeo.HelperLib.Documentation/OmegaLeo.HelperLib.Documentation.csproj" -c Release /p:Version=${{ inputs.tag_name }}
|
||||
- name: Publish to GitHub Packages
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Documentation/bin/Release/OmegaLeo.HelperLib.Documentation.${{ inputs.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
|
||||
|
||||
publish-shared-lib:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./OmegaLeo.HelperLib.Shared/OmegaLeo.HelperLib.Shared.csproj" -c Release /p:Version=${{ inputs.tag_name }}
|
||||
- name: Publish to GitHub Packages
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Shared/bin/Release/OmegaLeo.HelperLib.Shared.${{ inputs.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
|
||||
Executable
+149
@@ -0,0 +1,149 @@
|
||||
name: Publish Nuget Packages
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
run-name: "Publish version v${{github.event.release.tag_name}} to nuget"
|
||||
jobs:
|
||||
get-release:
|
||||
name: Get Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Get release
|
||||
id: get_release
|
||||
uses: bruceadams/get-release@v1.2.3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
outputs:
|
||||
upload_url: ${{ steps.get_release.outputs.upload_url }}
|
||||
publish-helper-lib:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [get-release]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Update Project Version
|
||||
run: sed -i "s/\(<Version>\([0-9]\+\.\)\{2\}\)\([0-9]\+\)/\1${{ github.event.release.tag_name }}/" "./OmegaLeo.HelperLib/OmegaLeo.HelperLib.csproj"
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./OmegaLeo.HelperLib/OmegaLeo.HelperLib.csproj" -c Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/omegaleo/OmegaLeo.HelperLib/releases/tag/${{ github.event.release.tag_name }}"
|
||||
- name: Publish Nuget Package
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib/bin/Release/OmegaLeo.HelperLib.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.nuget_api_key }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
- name: Publish to GitHub Packages
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib/bin/Release/OmegaLeo.HelperLib.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
|
||||
- name: Upload assets to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.get-release.outputs.upload_url }}
|
||||
asset_path: ./OmegaLeo.HelperLib/bin/Release/OmegaLeo.HelperLib.${{ github.event.release.tag_name }}.nupkg
|
||||
asset_name: OmegaLeo.HelperLib.${{ github.event.release.tag_name }}.nupkg
|
||||
asset_content_type: application/zip
|
||||
publish-changelog-lib:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ get-release ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Update Project Version
|
||||
run: sed -i "s/\(<Version>\([0-9]\+\.\)\{2\}\)\([0-9]\+\)/\1${{ github.event.release.tag_name }}/" "./OmegaLeo.HelperLib.Changelog/OmegaLeo.HelperLib.Changelog.csproj"
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./OmegaLeo.HelperLib.Changelog/OmegaLeo.HelperLib.Changelog.csproj" -c Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/omegaleo/OmegaLeo.HelperLib/releases/tag/${{ github.event.release.tag_name }}"
|
||||
- name: Publish Nuget Package
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Changelog/bin/Release/OmegaLeo.HelperLib.Changelog.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.nuget_api_key }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
- name: Publish to GitHub Packages
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Changelog/bin/Release/OmegaLeo.HelperLib.Changelog.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
|
||||
- name: Upload assets to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.get-release.outputs.upload_url }}
|
||||
asset_path: ./OmegaLeo.HelperLib.Changelog/bin/Release/OmegaLeo.HelperLib.Changelog.${{ github.event.release.tag_name }}.nupkg
|
||||
asset_name: OmegaLeo.HelperLib.Changelog.${{ github.event.release.tag_name }}.nupkg
|
||||
asset_content_type: application/zip
|
||||
publish-game-lib:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ get-release ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Update Project Version
|
||||
run: sed -i "s/\(<Version>\([0-9]\+\.\)\{2\}\)\([0-9]\+\)/\1${{ github.event.release.tag_name }}/" "./OmegaLeo.HelperLib.Game/OmegaLeo.HelperLib.Game.csproj"
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./OmegaLeo.HelperLib.Game/OmegaLeo.HelperLib.Game.csproj" -c Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/omegaleo/OmegaLeo.HelperLib/releases/tag/${{ github.event.release.tag_name }}"
|
||||
- name: Publish Nuget Package
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Game/bin/Release/OmegaLeo.HelperLib.Game.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.nuget_api_key }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
- name: Publish to GitHub Packages
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Game/bin/Release/OmegaLeo.HelperLib.Game.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
|
||||
- name: Upload assets to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.get-release.outputs.upload_url }}
|
||||
asset_path: ./OmegaLeo.HelperLib.Game/bin/Release/OmegaLeo.HelperLib.Game.${{ github.event.release.tag_name }}.nupkg
|
||||
asset_name: OmegaLeo.HelperLib.Game.${{ github.event.release.tag_name }}.nupkg
|
||||
asset_content_type: application/zip
|
||||
publish-doc-lib:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ get-release ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Update Project Version
|
||||
run: sed -i "s/\(<Version>\([0-9]\+\.\)\{2\}\)\([0-9]\+\)/\1${{ github.event.release.tag_name }}/" "./OmegaLeo.HelperLib.Documentation/OmegaLeo.HelperLib.Documentation.csproj"
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./OmegaLeo.HelperLib.Documentation/OmegaLeo.HelperLib.Documentation.csproj" -c Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/omegaleo/OmegaLeo.HelperLib/releases/tag/${{ github.event.release.tag_name }}"
|
||||
- name: Publish Nuget Package
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Documentation/bin/Release/OmegaLeo.HelperLib.Documentation.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.nuget_api_key }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
- name: Publish to GitHub Packages
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Documentation/bin/Release/OmegaLeo.HelperLib.Documentation.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
|
||||
- name: Upload assets to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.get-release.outputs.upload_url }}
|
||||
asset_path: ./OmegaLeo.HelperLib.Documentation/bin/Release/OmegaLeo.HelperLib.Documentation.${{ github.event.release.tag_name }}.nupkg
|
||||
asset_name: OmegaLeo.HelperLib.Documentation.${{ github.event.release.tag_name }}.nupkg
|
||||
asset_content_type: application/zip
|
||||
publish-shared-lib:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ get-release ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .Net Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Update Project Version
|
||||
run: sed -i "s/\(<Version>\([0-9]\+\.\)\{2\}\)\([0-9]\+\)/\1${{ github.event.release.tag_name }}/" "./OmegaLeo.HelperLib.Shared/OmegaLeo.HelperLib.Shared.csproj"
|
||||
- name: Create Nuget Package
|
||||
run: dotnet pack "./OmegaLeo.HelperLib.Shared/OmegaLeo.HelperLib.Shared.csproj" -c Release /p:Version=${{ github.event.release.tag_name }} /p:PackageReleaseNotes="See https://github.com/omegaleo/OmegaLeo.HelperLib/releases/tag/${{ github.event.release.tag_name }}"
|
||||
- name: Publish Nuget Package
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Shared/bin/Release/OmegaLeo.HelperLib.Shared.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.nuget_api_key }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
- name: Publish to GitHub Packages
|
||||
run: dotnet nuget push ./OmegaLeo.HelperLib.Shared/bin/Release/OmegaLeo.HelperLib.Shared.${{ github.event.release.tag_name }}.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/omegaleo/index.json --skip-duplicate
|
||||
- name: Upload assets to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.get-release.outputs.upload_url }}
|
||||
asset_path: ./OmegaLeo.HelperLib.Shared/bin/Release/OmegaLeo.HelperLib.Shared.${{ github.event.release.tag_name }}.nupkg
|
||||
asset_name: OmegaLeo.HelperLib.Shared.${{ github.event.release.tag_name }}.nupkg
|
||||
asset_content_type: application/zip
|
||||
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
|
||||
namespace OmegaLeo.HelperLib.Changelog.Models
|
||||
{
|
||||
[Serializable]
|
||||
public class Changelog
|
||||
{
|
||||
public string Target;
|
||||
|
||||
@@ -4,11 +4,8 @@ Lightweight Steamworks helper library for C# game projects.
|
||||
This package provides a simple Steam API wrapper for common tasks like initialization, callback processing, player name lookup, and achievements.
|
||||
|
||||
## Features
|
||||
- Simple Steam initialization via `SteamManager.Instance` (uses `SteamAPI_InitFlat` on SDK 1.58+ and reports the error message in `InitErrorMessage`)
|
||||
- Configurable native library location with `SteamManager.ConfigureLibraryPath()` (Unity `Plugins/x86_64`, custom folders)
|
||||
- `SteamManager.RestartAppIfNecessary()` for launching through Steam
|
||||
- Per-frame manual callback dispatch with `SteamManager.Update()`: callback subscriptions, `OverlayActivated` event and async call results (`SteamManager.Instance.Callbacks`)
|
||||
- Ownership, DLC and language queries via `SteamManager.Instance.Apps` (ISteamApps)
|
||||
- Simple Steam initialization via `SteamManager.Instance`
|
||||
- Per-frame callback runner with `SteamManager.Update()`
|
||||
- Safe shutdown with `SteamManager.Shutdown()`
|
||||
- Player persona name access with `SteamManager.GetSteamName()`
|
||||
- Achievement helpers via `AchievementManager`
|
||||
@@ -92,119 +89,11 @@ var session = steam.Ugc.BeginUpdateSession(480, 123456789012345678UL)
|
||||
.WithContentFolder("/absolute/path/to/content")
|
||||
.WithPreviewFile("/absolute/path/to/preview.png");
|
||||
var submitCallHandle2 = session.Submit("Updated content", out var failedStep2);
|
||||
|
||||
// Ownership / language (ISteamApps)
|
||||
bool ownsDemo = steam.Apps.BIsSubscribedApp(480);
|
||||
bool hasDlc = steam.Apps.BIsDlcInstalled(123456);
|
||||
string language = steam.Apps.GetCurrentGameLanguage(); // "english", "portuguese", ...
|
||||
```
|
||||
|
||||
## Callbacks and async call results
|
||||
`SteamManager.Update()` runs Steam's manual dispatch loop (`SteamAPI_ManualDispatch_*`). Callbacks and async call results are delivered from `Update()`, on the thread that calls it. If the loaded `steam_api` has no manual dispatch exports, or you call `SteamManager.ConfigureManualDispatch(false)` before `Instance`, `Update()` falls back to `SteamAPI_RunCallbacks` and no events or results are delivered. The library never runs both.
|
||||
|
||||
```cs
|
||||
var steam = SteamManager.Instance;
|
||||
|
||||
// Typed overlay event (GameOverlayActivated_t)
|
||||
steam.OverlayActivated += overlay => Console.WriteLine($"Overlay open: {overlay.Active}");
|
||||
|
||||
// Any callback by id, with the raw payload
|
||||
IDisposable sub = steam.Callbacks.Subscribe(SteamCallbackIds.GameOverlayActivated, data =>
|
||||
{
|
||||
bool active = data.ReadBoolean(0);
|
||||
});
|
||||
sub.Dispose(); // unsubscribe
|
||||
|
||||
// Workshop results: callback style...
|
||||
steam.Ugc.SubmitItemUpdate(updateHandle, "Patch notes", result =>
|
||||
{
|
||||
if (result.IsSuccess) Console.WriteLine($"Uploaded {result.PublishedFileId}");
|
||||
if (result.UserNeedsToAcceptWorkshopLegalAgreement) { /* show the agreement link */ }
|
||||
});
|
||||
steam.Ugc.CreateItem(480, 0 /* k_EWorkshopFileTypeCommunity */, created => { /* created.PublishedFileId */ });
|
||||
steam.Ugc.SendQueryUgcRequest(queryHandle, query => { /* query.NumResultsReturned */ });
|
||||
|
||||
// ...or awaitable (keep calling Update() while waiting)
|
||||
var query = await steam.Ugc.SendQueryUgcRequestAsync(queryHandle);
|
||||
|
||||
// Any other SteamAPICall_t handle
|
||||
var raw = await steam.Callbacks.WaitForCallResultAsync(apiCallHandle);
|
||||
if (!raw.IoFailure) { int eResult = raw.ReadInt32(0); }
|
||||
```
|
||||
|
||||
Callback structs use 8-byte packing on Windows and 4-byte packing on Linux, Steam Deck and macOS, which moves 64-bit fields in some structs. The typed results handle this. When you parse a raw payload yourself, check `SteamCallbackDispatcher.UsesLargeCallbackPack`.
|
||||
|
||||
## Using in Unity
|
||||
The library has no Unity references; add the DLLs and the Steam native libraries (`steam_api64.dll` for Windows, `libsteam_api.so` for Linux) to `Assets/Plugins/x86_64/` and set their platforms in the import settings. Keep all Steam code behind your Steam-off define (for example `DISABLESTEAMWORKS`) so itch / Microsoft Store builds don't touch it.
|
||||
|
||||
```cs
|
||||
#if !DISABLESTEAMWORKS
|
||||
using System.IO;
|
||||
using OmegaLeo.HelperLib.Steamworks;
|
||||
using UnityEngine;
|
||||
|
||||
public class SteamBootstrap : MonoBehaviour
|
||||
{
|
||||
private const uint AppId = 480; // your AppId (full game and demo have different ids)
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
DontDestroyOnLoad(gameObject);
|
||||
|
||||
// Player: <Game>_Data/Plugins/x86_64 (some Linux layouts use <Game>_Data/Plugins).
|
||||
// Editor: Application.dataPath is Assets/, so this finds Assets/Plugins/x86_64.
|
||||
SteamManager.ConfigureLibraryPath(Path.Combine(Application.dataPath, "Plugins", "x86_64"));
|
||||
SteamManager.ConfigureLibraryPath(Path.Combine(Application.dataPath, "Plugins"));
|
||||
|
||||
#if !UNITY_EDITOR
|
||||
// Relaunch through Steam when started from the exe. Call before ConfigureAppId.
|
||||
if (SteamManager.RestartAppIfNecessary(AppId))
|
||||
{
|
||||
Application.Quit();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
||||
// Editor/dev only: writes steam_appid.txt. Shipped builds get the AppId from Steam.
|
||||
SteamManager.ConfigureAppId(AppId, writeSteamAppIdFile: true);
|
||||
#endif
|
||||
|
||||
var steam = SteamManager.Instance;
|
||||
if (!steam.IsSteamworksInitialized)
|
||||
{
|
||||
Debug.LogWarning($"Steam not available: {steam.InitErrorMessage}");
|
||||
return;
|
||||
}
|
||||
|
||||
steam.OverlayActivated += OnOverlayActivated;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
SteamManager.Instance.Update(); // every frame, main thread
|
||||
}
|
||||
|
||||
private void OnOverlayActivated(SteamOverlayActivated overlay)
|
||||
{
|
||||
Time.timeScale = overlay.Active ? 0f : 1f; // or your own pause logic
|
||||
}
|
||||
|
||||
private void OnApplicationQuit()
|
||||
{
|
||||
SteamManager.Instance.OverlayActivated -= OnOverlayActivated;
|
||||
SteamManager.Instance.Shutdown();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
Pass an `ILogger` to `SteamManager.ConfigureLogger` (a small adapter around `Debug.Log`) to see which library path loaded and why init failed.
|
||||
|
||||
## Notes
|
||||
- Steam must be running and your app must be launched in a valid Steam context.
|
||||
- Configure your AppId, library path and dispatch mode before first access to `SteamManager.Instance`.
|
||||
- `ConfigureAppId(appId)` only sets the `SteamAppId` / `SteamGameId` environment variables. Use `ConfigureAppId(appId, writeSteamAppIdFile: true)` to also write `steam_appid.txt` (development only; a shipped build with that file skips `RestartAppIfNecessary`).
|
||||
- Configure your AppId before first access to `SteamManager.Instance`.
|
||||
- `SteamManager.Update()` should be called continuously during runtime.
|
||||
- If Steam is unavailable, `GetSteamName()` falls back to `"Player"`.
|
||||
|
||||
|
||||
@@ -1,480 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OmegaLeo.HelperLib.Shared.Attributes;
|
||||
|
||||
namespace OmegaLeo.HelperLib.Steamworks
|
||||
{
|
||||
[Documentation(nameof(SteamCallbackIds), "Steamworks callback ids (the k_iCallback value of each callback struct) used by this library.", null, null)]
|
||||
public static class SteamCallbackIds
|
||||
{
|
||||
[Documentation(nameof(GameOverlayActivated), "GameOverlayActivated_t (k_iSteamFriendsCallbacks + 31).", null, null)]
|
||||
public const int GameOverlayActivated = 331;
|
||||
|
||||
[Documentation(nameof(SteamApiCallCompleted), "SteamAPICallCompleted_t (k_iSteamUtilsCallbacks + 3). Handled internally to deliver async call results.", null, null)]
|
||||
public const int SteamApiCallCompleted = 703;
|
||||
|
||||
[Documentation(nameof(SteamUgcQueryCompleted), "SteamUGCQueryCompleted_t (k_iSteamUGCCallbacks + 1), the result of SendQueryUGCRequest.", null, null)]
|
||||
public const int SteamUgcQueryCompleted = 3401;
|
||||
|
||||
[Documentation(nameof(CreateItemResult), "CreateItemResult_t (k_iSteamUGCCallbacks + 3), the result of CreateItem.", null, null)]
|
||||
public const int CreateItemResult = 3403;
|
||||
|
||||
[Documentation(nameof(SubmitItemUpdateResult), "SubmitItemUpdateResult_t (k_iSteamUGCCallbacks + 4), the result of SubmitItemUpdate.", null, null)]
|
||||
public const int SubmitItemUpdateResult = 3404;
|
||||
}
|
||||
|
||||
[Documentation(nameof(SteamCallbackPayload), "Base class for a copied Steam callback payload with little-endian field readers. Offsets follow the native struct layout for the current platform (see SteamCallbackDispatcher.UsesLargeCallbackPack).", null, null)]
|
||||
public abstract class SteamCallbackPayload
|
||||
{
|
||||
protected SteamCallbackPayload(byte[] payload)
|
||||
{
|
||||
Payload = payload ?? Array.Empty<byte>();
|
||||
}
|
||||
|
||||
[Documentation(nameof(Payload), "Raw bytes of the native callback struct, copied before Steam frees it.", null, null)]
|
||||
public byte[] Payload { get; }
|
||||
|
||||
[Documentation(nameof(ReadByte), "Reads a byte at the given offset, or 0 when out of range.", new[] { "offset: Byte offset in the payload." }, null)]
|
||||
public byte ReadByte(int offset)
|
||||
{
|
||||
return offset >= 0 && offset < Payload.Length ? Payload[offset] : (byte)0;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ReadBoolean), "Reads a one-byte C++ bool at the given offset.", new[] { "offset: Byte offset in the payload." }, null)]
|
||||
public bool ReadBoolean(int offset)
|
||||
{
|
||||
return ReadByte(offset) != 0;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ReadInt32), "Reads a 32-bit signed integer at the given offset, or 0 when out of range.", new[] { "offset: Byte offset in the payload." }, null)]
|
||||
public int ReadInt32(int offset)
|
||||
{
|
||||
return HasBytes(offset, 4) ? BitConverter.ToInt32(Payload, offset) : 0;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ReadUInt32), "Reads a 32-bit unsigned integer at the given offset, or 0 when out of range.", new[] { "offset: Byte offset in the payload." }, null)]
|
||||
public uint ReadUInt32(int offset)
|
||||
{
|
||||
return HasBytes(offset, 4) ? BitConverter.ToUInt32(Payload, offset) : 0;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ReadUInt64), "Reads a 64-bit unsigned integer at the given offset, or 0 when out of range.", new[] { "offset: Byte offset in the payload." }, null)]
|
||||
public ulong ReadUInt64(int offset)
|
||||
{
|
||||
return HasBytes(offset, 8) ? BitConverter.ToUInt64(Payload, offset) : 0;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ReadString), "Reads a NUL-terminated UTF-8 char array field.", new[] { "offset: Byte offset of the char array.", "maxLength: Size of the char array in the native struct." }, null)]
|
||||
public string ReadString(int offset, int maxLength)
|
||||
{
|
||||
if (offset < 0 || offset >= Payload.Length || maxLength <= 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var end = Math.Min(Payload.Length, offset + maxLength);
|
||||
var length = 0;
|
||||
while (offset + length < end && Payload[offset + length] != 0)
|
||||
{
|
||||
length++;
|
||||
}
|
||||
|
||||
return Encoding.UTF8.GetString(Payload, offset, length);
|
||||
}
|
||||
|
||||
private bool HasBytes(int offset, int size)
|
||||
{
|
||||
return offset >= 0 && offset + size <= Payload.Length;
|
||||
}
|
||||
}
|
||||
|
||||
[Documentation(nameof(SteamCallbackData), "A Steam callback received through manual dispatch.", null, null)]
|
||||
public sealed class SteamCallbackData : SteamCallbackPayload
|
||||
{
|
||||
internal SteamCallbackData(int callbackId, int steamUser, byte[] payload) : base(payload)
|
||||
{
|
||||
CallbackId = callbackId;
|
||||
SteamUser = steamUser;
|
||||
}
|
||||
|
||||
[Documentation(nameof(CallbackId), "The callback id (k_iCallback) of the native struct.", null, null)]
|
||||
public int CallbackId { get; }
|
||||
|
||||
[Documentation(nameof(SteamUser), "The HSteamUser the callback was posted for.", null, null)]
|
||||
public int SteamUser { get; }
|
||||
}
|
||||
|
||||
[Documentation(nameof(SteamApiCallResult), "The completed result of an asynchronous Steam API call (SteamAPICall_t).", null, null)]
|
||||
public sealed class SteamApiCallResult : SteamCallbackPayload
|
||||
{
|
||||
internal SteamApiCallResult(ulong apiCall, int callbackId, bool ioFailure, byte[] payload) : base(payload)
|
||||
{
|
||||
ApiCall = apiCall;
|
||||
CallbackId = callbackId;
|
||||
IoFailure = ioFailure;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ApiCall), "The SteamAPICall_t handle this result belongs to.", null, null)]
|
||||
public ulong ApiCall { get; }
|
||||
|
||||
[Documentation(nameof(CallbackId), "The callback id of the result struct (for example SteamCallbackIds.SubmitItemUpdateResult).", null, null)]
|
||||
public int CallbackId { get; }
|
||||
|
||||
[Documentation(nameof(IoFailure), "True when Steam reported a failure fetching the result, or Steam was shut down before it completed. The payload is then not valid.", null, null)]
|
||||
public bool IoFailure { get; }
|
||||
|
||||
internal static SteamApiCallResult Failed(ulong apiCall)
|
||||
{
|
||||
return new SteamApiCallResult(apiCall, 0, true, Array.Empty<byte>());
|
||||
}
|
||||
}
|
||||
|
||||
[Documentation(nameof(SteamOverlayActivated), "Data from GameOverlayActivated_t, raised when the Steam overlay opens or closes.", null, null)]
|
||||
public readonly struct SteamOverlayActivated
|
||||
{
|
||||
internal SteamOverlayActivated(bool active, bool userInitiated, uint appId)
|
||||
{
|
||||
Active = active;
|
||||
UserInitiated = userInitiated;
|
||||
AppId = appId;
|
||||
}
|
||||
|
||||
[Documentation(nameof(Active), "True when the overlay was opened, false when it was closed.", null, null)]
|
||||
public bool Active { get; }
|
||||
|
||||
[Documentation(nameof(UserInitiated), "True when the user opened the overlay (as opposed to the game or Steam).", null, null)]
|
||||
public bool UserInitiated { get; }
|
||||
|
||||
[Documentation(nameof(AppId), "The AppId the overlay was activated for.", null, null)]
|
||||
public uint AppId { get; }
|
||||
}
|
||||
|
||||
[Documentation(nameof(SteamCallbackDispatcher), "Runs the Steam manual callback dispatch loop and delivers callbacks and async call results. Access it through SteamManager.Instance.Callbacks; it is pumped by SteamManager.Update().", null,
|
||||
@"```csharp
|
||||
var steam = SteamManager.Instance;
|
||||
steam.Callbacks.OverlayActivated += overlay => Pause(overlay.Active);
|
||||
using var sub = steam.Callbacks.Subscribe(SteamCallbackIds.GameOverlayActivated, data => Log(data.ReadBoolean(0)));
|
||||
var result = await steam.Callbacks.WaitForCallResultAsync(apiCallHandle);
|
||||
```")]
|
||||
public sealed class SteamCallbackDispatcher
|
||||
{
|
||||
private readonly object _sync = new object();
|
||||
private readonly Dictionary<int, List<Action<SteamCallbackData>>> _handlers = new Dictionary<int, List<Action<SteamCallbackData>>>();
|
||||
private readonly Dictionary<ulong, List<Action<SteamApiCallResult>>> _pendingCallResults = new Dictionary<ulong, List<Action<SteamApiCallResult>>>();
|
||||
|
||||
internal SteamCallbackDispatcher()
|
||||
{
|
||||
}
|
||||
|
||||
[Documentation(nameof(UsesLargeCallbackPack), "True when Steam callback structs use 8-byte packing (Windows). Linux, Steam Deck and macOS use 4-byte packing, which moves 64-bit fields in some structs.", null, null)]
|
||||
public static bool UsesLargeCallbackPack => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
|
||||
[Documentation(nameof(IsManualDispatchActive), "True when manual dispatch is running, so callbacks and async call results are delivered.", null, null)]
|
||||
public bool IsManualDispatchActive => SteamNativeApi.IsManualDispatchActive;
|
||||
|
||||
[Documentation(nameof(PendingCallResultCount), "Number of async call handles still waiting for a result.", null, null)]
|
||||
public int PendingCallResultCount
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
return _pendingCallResults.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Documentation(nameof(OverlayActivated), "Raised from SteamManager.Update() when the Steam overlay opens or closes (GameOverlayActivated_t). Use it to pause the game.", null, null)]
|
||||
public event Action<SteamOverlayActivated> OverlayActivated;
|
||||
|
||||
[Documentation(nameof(Subscribe), "Subscribes to every callback with the given id. The handler receives a copy of the raw payload. Dispose the returned object to unsubscribe.", new[]
|
||||
{
|
||||
"callbackId: Callback id (k_iCallback), see SteamCallbackIds.",
|
||||
"handler: Called from SteamManager.Update() for each matching callback."
|
||||
}, null)]
|
||||
public IDisposable Subscribe(int callbackId, Action<SteamCallbackData> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(handler));
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_handlers.TryGetValue(callbackId, out var list))
|
||||
{
|
||||
list = new List<Action<SteamCallbackData>>();
|
||||
_handlers[callbackId] = list;
|
||||
}
|
||||
|
||||
list.Add(handler);
|
||||
}
|
||||
|
||||
return new Subscription(() => Unsubscribe(callbackId, handler));
|
||||
}
|
||||
|
||||
[Documentation(nameof(Unsubscribe), "Removes a handler added with Subscribe.", new[] { "callbackId: Callback id the handler was registered for.", "handler: The handler to remove." }, null)]
|
||||
public bool Unsubscribe(int callbackId, Action<SteamCallbackData> handler)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_handlers.TryGetValue(callbackId, out var list) || !list.Remove(handler))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (list.Count == 0)
|
||||
{
|
||||
_handlers.Remove(callbackId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Documentation(nameof(RegisterCallResult), "Registers a handler for the result of an async Steam API call. The handler runs once, from SteamManager.Update(). Returns false when the handle is invalid or manual dispatch is not active.", new[]
|
||||
{
|
||||
"apiCall: SteamAPICall_t handle returned by an async Steam API method.",
|
||||
"onCompleted: Called with the result (check IoFailure)."
|
||||
}, null)]
|
||||
public bool RegisterCallResult(ulong apiCall, Action<SteamApiCallResult> onCompleted)
|
||||
{
|
||||
if (onCompleted == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(onCompleted));
|
||||
}
|
||||
|
||||
if (apiCall == 0 || !IsManualDispatchActive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_pendingCallResults.TryGetValue(apiCall, out var list))
|
||||
{
|
||||
list = new List<Action<SteamApiCallResult>>();
|
||||
_pendingCallResults[apiCall] = list;
|
||||
}
|
||||
|
||||
list.Add(onCompleted);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Documentation(nameof(WaitForCallResultAsync), "Returns a task that completes with the result of an async Steam API call. Keep calling SteamManager.Update() while waiting. Faults with InvalidOperationException when manual dispatch is not active.", new[]
|
||||
{
|
||||
"apiCall: SteamAPICall_t handle returned by an async Steam API method.",
|
||||
"cancellationToken: Cancels the wait (the Steam call itself keeps running)."
|
||||
}, null)]
|
||||
public Task<SteamApiCallResult> WaitForCallResultAsync(ulong apiCall, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (apiCall == 0)
|
||||
{
|
||||
return Task.FromException<SteamApiCallResult>(new ArgumentException("The Steam API call handle is invalid.", nameof(apiCall)));
|
||||
}
|
||||
|
||||
var completion = new TaskCompletionSource<SteamApiCallResult>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
Action<SteamApiCallResult> handler = result => completion.TrySetResult(result);
|
||||
if (!RegisterCallResult(apiCall, handler))
|
||||
{
|
||||
return Task.FromException<SteamApiCallResult>(new InvalidOperationException("Steam manual callback dispatch is not active, so async call results cannot be delivered."));
|
||||
}
|
||||
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
var registration = cancellationToken.Register(() =>
|
||||
{
|
||||
RemoveCallResult(apiCall, handler);
|
||||
completion.TrySetCanceled(cancellationToken);
|
||||
});
|
||||
completion.Task.ContinueWith(_ => registration.Dispose(), TaskScheduler.Default);
|
||||
}
|
||||
|
||||
return completion.Task;
|
||||
}
|
||||
|
||||
internal void RunFrame()
|
||||
{
|
||||
if (!SteamNativeApi.IsManualDispatchActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SteamNativeApi.ManualDispatchRunFrame();
|
||||
while (SteamNativeApi.ManualDispatchGetNextCallback(out var message))
|
||||
{
|
||||
try
|
||||
{
|
||||
HandleCallback(message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SteamManager.Logger.LogError(e, "An exception occurred while handling Steam callback {CallbackId}.", message.CallbackId);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SteamNativeApi.ManualDispatchFreeLastCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void FailPendingCallResults()
|
||||
{
|
||||
List<KeyValuePair<ulong, List<Action<SteamApiCallResult>>>> pending;
|
||||
lock (_sync)
|
||||
{
|
||||
pending = new List<KeyValuePair<ulong, List<Action<SteamApiCallResult>>>>(_pendingCallResults);
|
||||
_pendingCallResults.Clear();
|
||||
}
|
||||
|
||||
foreach (var entry in pending)
|
||||
{
|
||||
InvokeCallResultHandlers(entry.Value, SteamApiCallResult.Failed(entry.Key));
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCallback(SteamNativeCallbackMessage message)
|
||||
{
|
||||
var payload = CopyPayload(message.Param, message.ParamSize);
|
||||
var data = new SteamCallbackData(message.CallbackId, message.SteamUser, payload);
|
||||
|
||||
if (message.CallbackId == SteamCallbackIds.SteamApiCallCompleted)
|
||||
{
|
||||
HandleApiCallCompleted(data);
|
||||
}
|
||||
else if (message.CallbackId == SteamCallbackIds.GameOverlayActivated)
|
||||
{
|
||||
// GameOverlayActivated_t { uint8 m_bActive; bool m_bUserInitiated; AppId_t m_nAppID; uint32 m_dwOverlayPID; }
|
||||
try
|
||||
{
|
||||
OverlayActivated?.Invoke(new SteamOverlayActivated(data.ReadBoolean(0), data.ReadBoolean(1), data.ReadUInt32(4)));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SteamManager.Logger.LogError(e, "An OverlayActivated handler threw.");
|
||||
}
|
||||
}
|
||||
|
||||
Action<SteamCallbackData>[] handlers = null;
|
||||
lock (_sync)
|
||||
{
|
||||
if (_handlers.TryGetValue(message.CallbackId, out var list))
|
||||
{
|
||||
handlers = list.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
if (handlers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var handler in handlers)
|
||||
{
|
||||
try
|
||||
{
|
||||
handler(data);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SteamManager.Logger.LogError(e, "A subscriber threw while handling Steam callback {CallbackId}.", message.CallbackId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleApiCallCompleted(SteamCallbackData data)
|
||||
{
|
||||
// SteamAPICallCompleted_t { SteamAPICall_t m_hAsyncCall; int m_iCallback; uint32 m_cubParam; } - same layout under pack 4 and 8.
|
||||
var apiCall = data.ReadUInt64(0);
|
||||
var expectedCallback = data.ReadInt32(8);
|
||||
var resultSize = (int)data.ReadUInt32(12);
|
||||
|
||||
List<Action<SteamApiCallResult>> handlers;
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_pendingCallResults.TryGetValue(apiCall, out handlers))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_pendingCallResults.Remove(apiCall);
|
||||
}
|
||||
|
||||
var buffer = Marshal.AllocHGlobal(Math.Max(resultSize, 1));
|
||||
SteamApiCallResult result;
|
||||
try
|
||||
{
|
||||
var fetched = SteamNativeApi.ManualDispatchGetApiCallResult(apiCall, buffer, resultSize, expectedCallback, out var failed);
|
||||
result = fetched
|
||||
? new SteamApiCallResult(apiCall, expectedCallback, failed, CopyPayload(buffer, resultSize))
|
||||
: new SteamApiCallResult(apiCall, expectedCallback, true, Array.Empty<byte>());
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(buffer);
|
||||
}
|
||||
|
||||
InvokeCallResultHandlers(handlers, result);
|
||||
}
|
||||
|
||||
private void RemoveCallResult(ulong apiCall, Action<SteamApiCallResult> handler)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (_pendingCallResults.TryGetValue(apiCall, out var list) && list.Remove(handler) && list.Count == 0)
|
||||
{
|
||||
_pendingCallResults.Remove(apiCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void InvokeCallResultHandlers(List<Action<SteamApiCallResult>> handlers, SteamApiCallResult result)
|
||||
{
|
||||
foreach (var handler in handlers)
|
||||
{
|
||||
try
|
||||
{
|
||||
handler(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SteamManager.Logger.LogError(e, "A handler threw while handling the result of Steam API call {ApiCall}.", result.ApiCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] CopyPayload(IntPtr source, int size)
|
||||
{
|
||||
if (source == IntPtr.Zero || size <= 0)
|
||||
{
|
||||
return Array.Empty<byte>();
|
||||
}
|
||||
|
||||
var payload = new byte[size];
|
||||
Marshal.Copy(source, payload, 0, size);
|
||||
return payload;
|
||||
}
|
||||
|
||||
private sealed class Subscription : IDisposable
|
||||
{
|
||||
private Action _dispose;
|
||||
|
||||
public Subscription(Action dispose)
|
||||
{
|
||||
_dispose = dispose;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Interlocked.Exchange(ref _dispose, null)?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -356,59 +356,6 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
}
|
||||
}
|
||||
|
||||
[Documentation(nameof(SteamAppsManager), "Provides ownership, DLC and language queries from ISteamApps.", null,
|
||||
@"```csharp
|
||||
var apps = SteamManager.Instance.Apps;
|
||||
if (apps.BIsSubscribedApp(5498630)) { /* user owns the demo */ }
|
||||
var language = apps.GetCurrentGameLanguage(); // e.g. ""english""
|
||||
```")]
|
||||
public class SteamAppsManager
|
||||
{
|
||||
public bool IsAvailable => SteamNativeApi.IsSteamAppsAvailable();
|
||||
|
||||
[Documentation(nameof(BIsSubscribed), "Checks whether the current user owns (is subscribed to) the running app.", null, null)]
|
||||
public bool BIsSubscribed()
|
||||
{
|
||||
return SteamNativeApi.AppsIsSubscribed();
|
||||
}
|
||||
|
||||
[Documentation(nameof(BIsSubscribedApp), "Checks whether the current user owns the given app, for example a related demo or another of your games.",new[] { "appId: AppId to check." }, null)]
|
||||
public bool BIsSubscribedApp(uint appId)
|
||||
{
|
||||
return SteamNativeApi.AppsIsSubscribedApp(appId);
|
||||
}
|
||||
|
||||
[Documentation(nameof(BIsDlcInstalled), "Checks whether the user owns the given DLC and it is installed.", new[] { "appId: DLC AppId." }, null)]
|
||||
public bool BIsDlcInstalled(uint appId)
|
||||
{
|
||||
return SteamNativeApi.AppsIsDlcInstalled(appId);
|
||||
}
|
||||
|
||||
[Documentation(nameof(BIsAppInstalled), "Checks whether the given app is installed on this machine.", new[] { "appId: AppId to check." }, null)]
|
||||
public bool BIsAppInstalled(uint appId)
|
||||
{
|
||||
return SteamNativeApi.AppsIsAppInstalled(appId);
|
||||
}
|
||||
|
||||
[Documentation(nameof(GetCurrentGameLanguage), "Gets the language the user selected for this game in Steam (API language code such as \"english\"), or an empty string when unavailable.", null, null)]
|
||||
public string GetCurrentGameLanguage()
|
||||
{
|
||||
return SteamNativeApi.AppsGetCurrentGameLanguage();
|
||||
}
|
||||
|
||||
[Documentation(nameof(GetAvailableGameLanguages), "Gets a comma-separated list of the languages the game supports.", null, null)]
|
||||
public string GetAvailableGameLanguages()
|
||||
{
|
||||
return SteamNativeApi.AppsGetAvailableGameLanguages();
|
||||
}
|
||||
|
||||
[Documentation(nameof(GetAppBuildId), "Gets the Steam build id of the installed depot.", null, null)]
|
||||
public int GetAppBuildId()
|
||||
{
|
||||
return SteamNativeApi.AppsGetAppBuildId();
|
||||
}
|
||||
}
|
||||
|
||||
[Documentation(nameof(SteamUtilsManager), "Provides access checks for ISteamUtils.", null, null)]
|
||||
public class SteamUtilsManager
|
||||
{
|
||||
|
||||
@@ -5,13 +5,11 @@ using OmegaLeo.HelperLib.Shared.Attributes;
|
||||
|
||||
namespace OmegaLeo.HelperLib.Steamworks
|
||||
{
|
||||
[Documentation(nameof(SteamManager), "Manages Steamworks initialization, callback dispatch, and shutdown for applications using the Steam API.", null,
|
||||
[Documentation(nameof(SteamManager), "Manages Steamworks initialization, callback polling, and shutdown for applications using the Steam API.", null,
|
||||
@"```csharp
|
||||
SteamManager.ConfigureLogger(logger);
|
||||
SteamManager.ConfigureLibraryPath(pluginFolder);
|
||||
if (SteamManager.RestartAppIfNecessary(480)) { Quit(); return; }
|
||||
SteamManager.ConfigureAppId(480);
|
||||
var steam = SteamManager.Instance;
|
||||
steam.OverlayActivated += overlay => Pause(overlay.Active);
|
||||
steam.Update();
|
||||
```")]
|
||||
public class SteamManager
|
||||
@@ -19,8 +17,6 @@ steam.Update();
|
||||
private static SteamManager _instance;
|
||||
private static uint? _configuredAppId;
|
||||
private static ILogger _logger = NullLogger.Instance;
|
||||
private static readonly SteamCallbackDispatcher CallbackDispatcher = new SteamCallbackDispatcher();
|
||||
private static readonly SteamAppsManager AppsManager = new SteamAppsManager();
|
||||
private static readonly SteamUgcManager UgcManager = new SteamUgcManager();
|
||||
private static readonly SteamRemotePlayManager RemotePlayManager = new SteamRemotePlayManager();
|
||||
private static readonly SteamControllerManager ControllerManager = new SteamControllerManager();
|
||||
@@ -45,76 +41,14 @@ steam.Update();
|
||||
|
||||
internal static ILogger Logger => _logger;
|
||||
|
||||
internal static SteamCallbackDispatcher Dispatcher => CallbackDispatcher;
|
||||
|
||||
[Documentation(nameof(ConfigureLogger), "Configures the logger used by Steamworks helper classes.", new[] { "logger: ILogger instance to receive Steamworks logs." }, null)]
|
||||
public static void ConfigureLogger(ILogger logger)
|
||||
{
|
||||
_logger = logger ?? NullLogger.Instance;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ConfigureLibraryPath), "Adds a folder (or full file path) to search first for the Steam API native library (steam_api64.dll / libsteam_api.so / libsteam_api.dylib). Can be called several times; paths are tried in order, then the default locations. Must be called before Instance or RestartAppIfNecessary. Returns false when the library is already loaded.", new[] { "directoryOrFile: Folder containing the native library, or the full path to it." },
|
||||
@"```csharp
|
||||
SteamManager.ConfigureLibraryPath(Path.Combine(gameDataFolder, ""Plugins"", ""x86_64""));
|
||||
```")]
|
||||
public static bool ConfigureLibraryPath(string directoryOrFile)
|
||||
{
|
||||
if (!SteamNativeApi.AddLibrarySearchPath(directoryOrFile))
|
||||
{
|
||||
_logger.LogWarning("ConfigureLibraryPath ignored for '{SteamLibraryPath}': the path is empty or the Steam API library is already loaded.", directoryOrFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ConfigureManualDispatch), "Enables or disables manual callback dispatch (enabled by default). When disabled, Update() uses SteamAPI_RunCallbacks and no callback events or async call results are delivered. Must be called before Instance.", new[] { "enabled: True to use manual dispatch." }, null)]
|
||||
public static bool ConfigureManualDispatch(bool enabled)
|
||||
{
|
||||
return _instance == null && SteamNativeApi.ConfigureManualDispatch(enabled);
|
||||
}
|
||||
|
||||
[Documentation(nameof(RestartAppIfNecessary), "Calls SteamAPI_RestartAppIfNecessary. Returns true when the game was not launched through Steam and Steam is relaunching it: quit immediately in that case. Call it before Instance and before ConfigureAppId (steam_appid.txt, and possibly the SteamAppId environment variable, suppress the relaunch). Returns false when the native library cannot be loaded.", new[] { "appId: Your Steam AppId." },
|
||||
@"```csharp
|
||||
if (SteamManager.RestartAppIfNecessary(480))
|
||||
{
|
||||
Quit();
|
||||
return;
|
||||
}
|
||||
```")]
|
||||
public static bool RestartAppIfNecessary(uint appId)
|
||||
{
|
||||
if (appId == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_configuredAppId.HasValue)
|
||||
{
|
||||
_logger.LogWarning("RestartAppIfNecessary was called after ConfigureAppId; the AppId environment variables or steam_appid.txt may stop Steam from relaunching the game.");
|
||||
}
|
||||
|
||||
var restarting = SteamNativeApi.RestartAppIfNecessary(appId);
|
||||
if (restarting)
|
||||
{
|
||||
_logger.LogInformation("Steam is relaunching the game through the Steam client; the current process should exit.");
|
||||
}
|
||||
|
||||
return restarting;
|
||||
}
|
||||
|
||||
[Documentation(nameof(ConfigureAppId), "Configures the Steam AppId used during initialization by setting the SteamAppId/SteamGameId environment variables. Does not write steam_appid.txt. Must be called before accessing the singleton instance.", new[] { "appId: Steam application identifier." }, null)]
|
||||
[Documentation(nameof(ConfigureAppId), "Configures the Steam AppId used during initialization. Must be called before accessing the singleton instance.", new[] { "appId: Steam application identifier." }, null)]
|
||||
public static bool ConfigureAppId(uint appId)
|
||||
{
|
||||
return ConfigureAppId(appId, false);
|
||||
}
|
||||
|
||||
[Documentation(nameof(ConfigureAppId), "Configures the Steam AppId used during initialization. Optionally writes steam_appid.txt next to the executable and in the working directory (useful in editors and development builds; leave false for shipped builds). Must be called before accessing the singleton instance.", new[]
|
||||
{
|
||||
"appId: Steam application identifier.",
|
||||
"writeSteamAppIdFile: True to also write steam_appid.txt."
|
||||
}, null)]
|
||||
public static bool ConfigureAppId(uint appId, bool writeSteamAppIdFile)
|
||||
{
|
||||
if (appId == 0)
|
||||
{
|
||||
@@ -128,29 +62,13 @@ if (SteamManager.RestartAppIfNecessary(480))
|
||||
}
|
||||
|
||||
_configuredAppId = appId;
|
||||
SteamNativeApi.ConfigureAppId(appId, writeSteamAppIdFile);
|
||||
SteamNativeApi.ConfigureAppId(appId);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Documentation(nameof(IsSteamworksInitialized), "Indicates whether Steamworks is initialized and ready for API calls.", null, null)]
|
||||
public bool IsSteamworksInitialized { get; private set; }
|
||||
|
||||
[Documentation(nameof(InitErrorMessage), "The reason initialization failed, as reported by SteamAPI_InitFlat when available. Empty after a successful init.", null, null)]
|
||||
public string InitErrorMessage { get; private set; } = string.Empty;
|
||||
|
||||
[Documentation(nameof(Callbacks), "Provides callback subscriptions and async call results through manual dispatch.", null, null)]
|
||||
public SteamCallbackDispatcher Callbacks => CallbackDispatcher;
|
||||
|
||||
[Documentation(nameof(OverlayActivated), "Raised from Update() when the Steam overlay opens or closes. Same as Callbacks.OverlayActivated.", null, null)]
|
||||
public event Action<SteamOverlayActivated> OverlayActivated
|
||||
{
|
||||
add => CallbackDispatcher.OverlayActivated += value;
|
||||
remove => CallbackDispatcher.OverlayActivated -= value;
|
||||
}
|
||||
|
||||
[Documentation(nameof(Apps), "Provides access to ISteamApps bindings (ownership, DLC, language).", null, null)]
|
||||
public SteamAppsManager Apps => AppsManager;
|
||||
|
||||
[Documentation(nameof(Ugc), "Provides access to Steam Workshop (UGC) helper operations.", null, null)]
|
||||
public SteamUgcManager Ugc => UgcManager;
|
||||
|
||||
@@ -216,12 +134,11 @@ if (SteamManager.RestartAppIfNecessary(480))
|
||||
if (SteamNativeApi.Initialize(_configuredAppId))
|
||||
{
|
||||
IsSteamworksInitialized = true;
|
||||
_logger.LogInformation("Steamworks initialized successfully (manual callback dispatch: {ManualDispatchActive}).", SteamNativeApi.IsManualDispatchActive);
|
||||
_logger.LogInformation("Steamworks initialized successfully.");
|
||||
}
|
||||
else
|
||||
{
|
||||
InitErrorMessage = SteamNativeApi.LastInitErrorMessage;
|
||||
_logger.LogWarning("Steamworks initialization failed: {InitErrorMessage} Ensure Steam is running and AppId context is valid.", InitErrorMessage);
|
||||
_logger.LogWarning("Steamworks initialization failed. Ensure Steam is running and AppId context is valid.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -231,30 +148,20 @@ if (SteamManager.RestartAppIfNecessary(480))
|
||||
}
|
||||
|
||||
// This must be called from your game's main loop (e.g., Update in Unity/Godot)
|
||||
[Documentation(nameof(Update), "Executes Steamworks callbacks (manual dispatch, or SteamAPI_RunCallbacks when manual dispatch is unavailable) and delivers events and async call results. Call every frame from your game loop's main thread.", null, null)]
|
||||
[Documentation(nameof(Update), "Executes Steamworks callbacks. Call every frame from your game loop.", null, null)]
|
||||
public void Update()
|
||||
{
|
||||
if (!IsSteamworksInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SteamNativeApi.IsManualDispatchActive)
|
||||
{
|
||||
CallbackDispatcher.RunFrame();
|
||||
}
|
||||
else
|
||||
if (IsSteamworksInitialized)
|
||||
{
|
||||
SteamNativeApi.RunCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
[Documentation(nameof(Shutdown), "Shuts down Steamworks and clears the initialized state. Pending async call results complete with IoFailure = true.", null, null)]
|
||||
[Documentation(nameof(Shutdown), "Shuts down Steamworks and clears the initialized state.", null, null)]
|
||||
public void Shutdown()
|
||||
{
|
||||
if (IsSteamworksInitialized)
|
||||
{
|
||||
CallbackDispatcher.FailPendingCallResults();
|
||||
SteamNativeApi.Shutdown();
|
||||
IsSteamworksInitialized = false;
|
||||
}
|
||||
|
||||
@@ -2,70 +2,18 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace OmegaLeo.HelperLib.Steamworks
|
||||
{
|
||||
internal readonly struct SteamNativeCallbackMessage
|
||||
{
|
||||
public SteamNativeCallbackMessage(int steamUser, int callbackId, IntPtr param, int paramSize)
|
||||
{
|
||||
SteamUser = steamUser;
|
||||
CallbackId = callbackId;
|
||||
Param = param;
|
||||
ParamSize = paramSize;
|
||||
}
|
||||
|
||||
public int SteamUser { get; }
|
||||
public int CallbackId { get; }
|
||||
public IntPtr Param { get; }
|
||||
public int ParamSize { get; }
|
||||
}
|
||||
|
||||
internal static class SteamNativeApi
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
private delegate bool SteamApiInitDelegate();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate int SteamApiInitFlatDelegate(IntPtr errorMessage);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
private delegate bool SteamApiRestartAppIfNecessaryDelegate(uint appId);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void SteamApiVoidDelegate();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate int SteamApiGetHSteamPipeDelegate();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate void SteamApiManualDispatchPipeDelegate(int steamPipe);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
private delegate bool SteamApiManualDispatchGetNextCallbackDelegate(int steamPipe, IntPtr callbackMessage);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
private delegate bool SteamApiManualDispatchGetApiCallResultDelegate(int steamPipe, ulong apiCall, IntPtr callbackBuffer, int callbackSize, int callbackExpected, [MarshalAs(UnmanagedType.I1)] out bool failed);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
private delegate bool SteamAppsBoolDelegate(IntPtr steamApps);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
private delegate bool SteamAppsAppIdBoolDelegate(IntPtr steamApps, uint appId);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate IntPtr SteamAppsStringDelegate(IntPtr steamApps);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate int SteamAppsGetAppBuildIdDelegate(IntPtr steamApps);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate IntPtr SteamFriendsAccessorDelegate();
|
||||
|
||||
@@ -341,41 +289,13 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
|
||||
private static readonly object SyncRoot = new object();
|
||||
|
||||
// SteamErrMsg is a char[1024] buffer in steam_api_common.h.
|
||||
private const int SteamErrMsgSize = 1024;
|
||||
|
||||
// Large enough for CallbackMsg_t on 32-bit and 64-bit (24 bytes on x64).
|
||||
private const int CallbackMessageBufferSize = 64;
|
||||
|
||||
private static IntPtr _libraryHandle;
|
||||
private static bool _libraryLoaded;
|
||||
private static bool _loadFailureLogged;
|
||||
private static bool _initialized;
|
||||
private static bool _manualDispatchEnabled = true;
|
||||
private static bool _manualDispatchActive;
|
||||
private static int _steamPipe;
|
||||
private static IntPtr _callbackMessageBuffer;
|
||||
|
||||
private static readonly List<string> CustomLibraryPaths = new List<string>();
|
||||
|
||||
private static SteamApiInitFlatDelegate _steamApiInitFlat;
|
||||
private static SteamApiInitDelegate _steamApiInit;
|
||||
private static SteamApiRestartAppIfNecessaryDelegate _steamApiRestartAppIfNecessary;
|
||||
private static SteamApiVoidDelegate _steamApiShutdown;
|
||||
private static SteamApiVoidDelegate _steamApiRunCallbacks;
|
||||
private static SteamApiGetHSteamPipeDelegate _steamApiGetHSteamPipe;
|
||||
private static SteamApiVoidDelegate _steamApiManualDispatchInit;
|
||||
private static SteamApiManualDispatchPipeDelegate _steamApiManualDispatchRunFrame;
|
||||
private static SteamApiManualDispatchGetNextCallbackDelegate _steamApiManualDispatchGetNextCallback;
|
||||
private static SteamApiManualDispatchPipeDelegate _steamApiManualDispatchFreeLastCallback;
|
||||
private static SteamApiManualDispatchGetApiCallResultDelegate _steamApiManualDispatchGetApiCallResult;
|
||||
private static SteamAppsBoolDelegate _steamAppsIsSubscribed;
|
||||
private static SteamAppsAppIdBoolDelegate _steamAppsIsSubscribedApp;
|
||||
private static SteamAppsAppIdBoolDelegate _steamAppsIsDlcInstalled;
|
||||
private static SteamAppsAppIdBoolDelegate _steamAppsIsAppInstalled;
|
||||
private static SteamAppsStringDelegate _steamAppsGetCurrentGameLanguage;
|
||||
private static SteamAppsStringDelegate _steamAppsGetAvailableGameLanguages;
|
||||
private static SteamAppsGetAppBuildIdDelegate _steamAppsGetAppBuildId;
|
||||
private static SteamFriendsAccessorDelegate _steamFriendsAccessor;
|
||||
private static SteamUserStatsAccessorDelegate _steamUserStatsAccessor;
|
||||
private static SteamUgcAccessorDelegate _steamUgcAccessor;
|
||||
@@ -465,7 +385,6 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
private static readonly Dictionary<string, SteamInterfaceAccessorDelegate> AdditionalInterfaceAccessors = new Dictionary<string, SteamInterfaceAccessorDelegate>();
|
||||
private static readonly Dictionary<string, IntPtr> AdditionalInterfacePointers = new Dictionary<string, IntPtr>();
|
||||
|
||||
private const string InterfaceSteamApps = "SteamApps";
|
||||
private const string InterfaceSteamController = "SteamController";
|
||||
private const string InterfaceSteamGameCoordinator = "SteamGameCoordinator";
|
||||
private const string InterfaceSteamGameServer = "SteamGameServer";
|
||||
@@ -484,53 +403,13 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
|
||||
public static bool IsAvailable => EnsureLoaded();
|
||||
|
||||
public static bool IsManualDispatchActive => _manualDispatchActive;
|
||||
|
||||
public static string LastInitErrorMessage { get; private set; } = string.Empty;
|
||||
|
||||
private static ILogger Logger => SteamManager.Logger;
|
||||
|
||||
public static bool AddLibrarySearchPath(string directoryOrFile)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(directoryOrFile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (_libraryLoaded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CustomLibraryPaths.Add(directoryOrFile);
|
||||
_loadFailureLogged = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ConfigureManualDispatch(bool enabled)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_manualDispatchEnabled = enabled;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Initialize(uint? appId = null)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (appId.HasValue && appId.Value > 0)
|
||||
{
|
||||
ApplyAppIdEnvironment(appId.Value);
|
||||
ConfigureAppId(appId.Value);
|
||||
}
|
||||
|
||||
if (_initialized)
|
||||
@@ -540,39 +419,25 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
|
||||
if (!EnsureLoaded())
|
||||
{
|
||||
LastInitErrorMessage = "The Steam API native library could not be loaded.";
|
||||
return false;
|
||||
}
|
||||
|
||||
_initialized = InvokeSteamApiInit();
|
||||
if (_steamApiInit == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_initialized = _steamApiInit();
|
||||
if (_initialized)
|
||||
{
|
||||
CacheInterfaces();
|
||||
TryEnableManualDispatch();
|
||||
}
|
||||
|
||||
return _initialized;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool RestartAppIfNecessary(uint appId)
|
||||
{
|
||||
if (!EnsureLoaded())
|
||||
{
|
||||
Logger.LogError("SteamAPI_RestartAppIfNecessary skipped: the Steam API native library could not be loaded.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_steamApiRestartAppIfNecessary == null)
|
||||
{
|
||||
Logger.LogWarning("SteamAPI_RestartAppIfNecessary export not found in the loaded Steam API library.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return _steamApiRestartAppIfNecessary(appId);
|
||||
}
|
||||
|
||||
public static void ConfigureAppId(uint appId, bool writeSteamAppIdFile)
|
||||
public static void ConfigureAppId(uint appId)
|
||||
{
|
||||
if (appId == 0)
|
||||
{
|
||||
@@ -582,12 +447,9 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
lock (SyncRoot)
|
||||
{
|
||||
ApplyAppIdEnvironment(appId);
|
||||
if (writeSteamAppIdFile)
|
||||
{
|
||||
TryWriteSteamAppIdFile(appId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Shutdown()
|
||||
{
|
||||
@@ -600,14 +462,6 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
|
||||
_steamApiShutdown?.Invoke();
|
||||
_initialized = false;
|
||||
_manualDispatchActive = false;
|
||||
_steamPipe = 0;
|
||||
if (_callbackMessageBuffer != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(_callbackMessageBuffer);
|
||||
_callbackMessageBuffer = IntPtr.Zero;
|
||||
}
|
||||
|
||||
_steamFriends = IntPtr.Zero;
|
||||
_steamUserStats = IntPtr.Zero;
|
||||
_steamUgc = IntPtr.Zero;
|
||||
@@ -618,8 +472,7 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
|
||||
public static void RunCallbacks()
|
||||
{
|
||||
// SteamAPI_RunCallbacks must never run once manual dispatch is in use.
|
||||
if (!_initialized || _manualDispatchActive)
|
||||
if (!_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -627,152 +480,6 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
_steamApiRunCallbacks?.Invoke();
|
||||
}
|
||||
|
||||
public static void ManualDispatchRunFrame()
|
||||
{
|
||||
if (!_manualDispatchActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_steamApiManualDispatchRunFrame(_steamPipe);
|
||||
}
|
||||
|
||||
public static bool ManualDispatchGetNextCallback(out SteamNativeCallbackMessage message)
|
||||
{
|
||||
message = default;
|
||||
|
||||
if (!_manualDispatchActive || !_steamApiManualDispatchGetNextCallback(_steamPipe, _callbackMessageBuffer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// CallbackMsg_t { HSteamUser m_hSteamUser; int m_iCallback; uint8 *m_pubParam; int m_cubParam; }
|
||||
// The pointer lands on offset 8 under both pack 4 and pack 8, so the layout is the same on every platform.
|
||||
message = new SteamNativeCallbackMessage(
|
||||
Marshal.ReadInt32(_callbackMessageBuffer, 0),
|
||||
Marshal.ReadInt32(_callbackMessageBuffer, 4),
|
||||
Marshal.ReadIntPtr(_callbackMessageBuffer, 8),
|
||||
Marshal.ReadInt32(_callbackMessageBuffer, 8 + IntPtr.Size));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void ManualDispatchFreeLastCallback()
|
||||
{
|
||||
if (!_manualDispatchActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_steamApiManualDispatchFreeLastCallback(_steamPipe);
|
||||
}
|
||||
|
||||
public static bool ManualDispatchGetApiCallResult(ulong apiCall, IntPtr callbackBuffer, int callbackSize, int callbackExpected, out bool failed)
|
||||
{
|
||||
failed = true;
|
||||
|
||||
if (!_manualDispatchActive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _steamApiManualDispatchGetApiCallResult(_steamPipe, apiCall, callbackBuffer, callbackSize, callbackExpected, out failed);
|
||||
}
|
||||
|
||||
private static bool InvokeSteamApiInit()
|
||||
{
|
||||
LastInitErrorMessage = string.Empty;
|
||||
|
||||
if (_steamApiInitFlat != null)
|
||||
{
|
||||
var errorBuffer = Marshal.AllocHGlobal(SteamErrMsgSize);
|
||||
try
|
||||
{
|
||||
Marshal.WriteByte(errorBuffer, 0, 0);
|
||||
var result = _steamApiInitFlat(errorBuffer);
|
||||
if (result == 0)
|
||||
{
|
||||
Logger.LogDebug("Steamworks initialized through SteamAPI_InitFlat.");
|
||||
return true;
|
||||
}
|
||||
|
||||
var message = Marshal.PtrToStringAnsi(errorBuffer) ?? string.Empty;
|
||||
LastInitErrorMessage = string.IsNullOrWhiteSpace(message) ? DescribeInitResult(result) : message;
|
||||
Logger.LogWarning("SteamAPI_InitFlat failed with {InitResult} ({InitResultName}): {InitErrorMessage}", result, DescribeInitResult(result), LastInitErrorMessage);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(errorBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steamApiInit != null)
|
||||
{
|
||||
if (_steamApiInit())
|
||||
{
|
||||
Logger.LogDebug("Steamworks initialized through the legacy SteamAPI_Init export.");
|
||||
return true;
|
||||
}
|
||||
|
||||
LastInitErrorMessage = "SteamAPI_Init returned false (this SDK version does not report a reason).";
|
||||
return false;
|
||||
}
|
||||
|
||||
LastInitErrorMessage = "No SteamAPI_InitFlat, SteamAPI_Init or SteamAPI_InitSafe export was found.";
|
||||
Logger.LogError(LastInitErrorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string DescribeInitResult(int result)
|
||||
{
|
||||
// ESteamAPIInitResult
|
||||
switch (result)
|
||||
{
|
||||
case 0: return "OK";
|
||||
case 1: return "FailedGeneric";
|
||||
case 2: return "NoSteamClient";
|
||||
case 3: return "VersionMismatch";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
private static void TryEnableManualDispatch()
|
||||
{
|
||||
if (!_manualDispatchEnabled)
|
||||
{
|
||||
Logger.LogInformation("Manual callback dispatch disabled; using SteamAPI_RunCallbacks.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_steamApiGetHSteamPipe == null ||
|
||||
_steamApiManualDispatchInit == null ||
|
||||
_steamApiManualDispatchRunFrame == null ||
|
||||
_steamApiManualDispatchGetNextCallback == null ||
|
||||
_steamApiManualDispatchFreeLastCallback == null ||
|
||||
_steamApiManualDispatchGetApiCallResult == null)
|
||||
{
|
||||
Logger.LogWarning("Steam manual dispatch exports not found; falling back to SteamAPI_RunCallbacks. Callback events and async call results will not be delivered.");
|
||||
return;
|
||||
}
|
||||
|
||||
var steamPipe = _steamApiGetHSteamPipe();
|
||||
if (steamPipe == 0)
|
||||
{
|
||||
Logger.LogWarning("SteamAPI_GetHSteamPipe returned an invalid pipe; falling back to SteamAPI_RunCallbacks.");
|
||||
return;
|
||||
}
|
||||
|
||||
_steamApiManualDispatchInit();
|
||||
_steamPipe = steamPipe;
|
||||
if (_callbackMessageBuffer == IntPtr.Zero)
|
||||
{
|
||||
_callbackMessageBuffer = Marshal.AllocHGlobal(CallbackMessageBufferSize);
|
||||
}
|
||||
|
||||
_manualDispatchActive = true;
|
||||
Logger.LogDebug("Steam manual callback dispatch enabled.");
|
||||
}
|
||||
|
||||
public static string GetPersonaName()
|
||||
{
|
||||
if (!EnsureReady())
|
||||
@@ -1077,8 +784,6 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
return _steamRemotePlayGetSessionClientResolution?.Invoke(_steamRemotePlay, sessionId, out resolutionX, out resolutionY) ?? false;
|
||||
}
|
||||
|
||||
public static bool IsSteamAppsAvailable() => EnsureAdditionalInterfaceReady(InterfaceSteamApps);
|
||||
|
||||
public static bool IsSteamControllerAvailable() => EnsureAdditionalInterfaceReady(InterfaceSteamController);
|
||||
|
||||
public static bool IsSteamFriendsAvailable() => EnsureFriendsReady();
|
||||
@@ -1223,85 +928,6 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
return _steamUtilsIsOverlayEnabled?.Invoke(steamUtils) ?? false;
|
||||
}
|
||||
|
||||
public static bool AppsIsSubscribed()
|
||||
{
|
||||
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
|
||||
return _steamAppsIsSubscribed?.Invoke(steamApps) ?? false;
|
||||
}
|
||||
|
||||
public static bool AppsIsSubscribedApp(uint appId)
|
||||
{
|
||||
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
|
||||
return _steamAppsIsSubscribedApp?.Invoke(steamApps, appId) ?? false;
|
||||
}
|
||||
|
||||
public static bool AppsIsDlcInstalled(uint appId)
|
||||
{
|
||||
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
|
||||
return _steamAppsIsDlcInstalled?.Invoke(steamApps, appId) ?? false;
|
||||
}
|
||||
|
||||
public static bool AppsIsAppInstalled(uint appId)
|
||||
{
|
||||
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
|
||||
return _steamAppsIsAppInstalled?.Invoke(steamApps, appId) ?? false;
|
||||
}
|
||||
|
||||
public static string AppsGetCurrentGameLanguage()
|
||||
{
|
||||
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
|
||||
var languagePtr = _steamAppsGetCurrentGameLanguage?.Invoke(steamApps) ?? IntPtr.Zero;
|
||||
return languagePtr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(languagePtr) ?? string.Empty;
|
||||
}
|
||||
|
||||
public static string AppsGetAvailableGameLanguages()
|
||||
{
|
||||
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
|
||||
var languagesPtr = _steamAppsGetAvailableGameLanguages?.Invoke(steamApps) ?? IntPtr.Zero;
|
||||
return languagesPtr == IntPtr.Zero ? string.Empty : Marshal.PtrToStringAnsi(languagesPtr) ?? string.Empty;
|
||||
}
|
||||
|
||||
public static int AppsGetAppBuildId()
|
||||
{
|
||||
if (!EnsureAdditionalInterfaceReady(InterfaceSteamApps))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var steamApps = GetAdditionalInterfacePointer(InterfaceSteamApps);
|
||||
return _steamAppsGetAppBuildId?.Invoke(steamApps) ?? 0;
|
||||
}
|
||||
|
||||
public static bool RemoteStorageFileExists(string fileName)
|
||||
{
|
||||
if (!EnsureAdditionalInterfaceReady(InterfaceSteamRemoteStorage))
|
||||
@@ -1860,66 +1486,35 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
return true;
|
||||
}
|
||||
|
||||
var failures = new List<string>();
|
||||
foreach (var candidate in GetLibraryCandidates())
|
||||
{
|
||||
try
|
||||
{
|
||||
var handle = LoadUnmanagedLibrary(candidate);
|
||||
if (handle != IntPtr.Zero)
|
||||
_libraryHandle = LoadUnmanagedLibrary(candidate);
|
||||
_libraryLoaded = _libraryHandle != IntPtr.Zero;
|
||||
if (_libraryLoaded)
|
||||
{
|
||||
_libraryHandle = handle;
|
||||
_libraryLoaded = true;
|
||||
BindDelegates();
|
||||
Logger.LogInformation("Loaded Steam API native library from '{SteamLibraryPath}'.", candidate);
|
||||
return true;
|
||||
}
|
||||
|
||||
failures.Add($"{candidate} ({GetLastLoadError()})");
|
||||
}
|
||||
catch (Exception e)
|
||||
catch
|
||||
{
|
||||
// Try the next candidate.
|
||||
failures.Add($"{candidate} ({e.GetType().Name}: {e.Message})");
|
||||
}
|
||||
}
|
||||
|
||||
if (!_loadFailureLogged)
|
||||
{
|
||||
_loadFailureLogged = true;
|
||||
Logger.LogError(
|
||||
"Could not load the Steam API native library '{SteamLibraryName}'. Call SteamManager.ConfigureLibraryPath with the folder that contains it. Tried: {SteamLibraryCandidates}",
|
||||
GetLibraryFileName(),
|
||||
string.Join("; ", failures));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void BindDelegates()
|
||||
{
|
||||
// SDK 1.58+ exposes SteamAPI_InitFlat (with an error message); older SDKs only have SteamAPI_Init/InitSafe.
|
||||
_steamApiInitFlat = Bind<SteamApiInitFlatDelegate>("SteamAPI_InitFlat");
|
||||
_steamApiInit =
|
||||
Bind<SteamApiInitDelegate>("SteamAPI_Init")
|
||||
?? Bind<SteamApiInitDelegate>("SteamAPI_InitSafe");
|
||||
_steamApiRestartAppIfNecessary = Bind<SteamApiRestartAppIfNecessaryDelegate>("SteamAPI_RestartAppIfNecessary");
|
||||
_steamApiShutdown = Bind<SteamApiVoidDelegate>("SteamAPI_Shutdown");
|
||||
_steamApiRunCallbacks = Bind<SteamApiVoidDelegate>("SteamAPI_RunCallbacks");
|
||||
_steamApiGetHSteamPipe = Bind<SteamApiGetHSteamPipeDelegate>("SteamAPI_GetHSteamPipe");
|
||||
_steamApiManualDispatchInit = Bind<SteamApiVoidDelegate>("SteamAPI_ManualDispatch_Init");
|
||||
_steamApiManualDispatchRunFrame = Bind<SteamApiManualDispatchPipeDelegate>("SteamAPI_ManualDispatch_RunFrame");
|
||||
_steamApiManualDispatchGetNextCallback = Bind<SteamApiManualDispatchGetNextCallbackDelegate>("SteamAPI_ManualDispatch_GetNextCallback");
|
||||
_steamApiManualDispatchFreeLastCallback = Bind<SteamApiManualDispatchPipeDelegate>("SteamAPI_ManualDispatch_FreeLastCallback");
|
||||
_steamApiManualDispatchGetApiCallResult = Bind<SteamApiManualDispatchGetApiCallResultDelegate>("SteamAPI_ManualDispatch_GetAPICallResult");
|
||||
_steamAppsIsSubscribed = Bind<SteamAppsBoolDelegate>("SteamAPI_ISteamApps_BIsSubscribed");
|
||||
_steamAppsIsSubscribedApp = Bind<SteamAppsAppIdBoolDelegate>("SteamAPI_ISteamApps_BIsSubscribedApp");
|
||||
_steamAppsIsDlcInstalled = Bind<SteamAppsAppIdBoolDelegate>("SteamAPI_ISteamApps_BIsDlcInstalled");
|
||||
_steamAppsIsAppInstalled = Bind<SteamAppsAppIdBoolDelegate>("SteamAPI_ISteamApps_BIsAppInstalled");
|
||||
_steamAppsGetCurrentGameLanguage = Bind<SteamAppsStringDelegate>("SteamAPI_ISteamApps_GetCurrentGameLanguage");
|
||||
_steamAppsGetAvailableGameLanguages = Bind<SteamAppsStringDelegate>("SteamAPI_ISteamApps_GetAvailableGameLanguages");
|
||||
_steamAppsGetAppBuildId = Bind<SteamAppsGetAppBuildIdDelegate>("SteamAPI_ISteamApps_GetAppBuildId");
|
||||
_steamFriendsAccessor = BindInterfaceAccessor<SteamFriendsAccessorDelegate>("SteamFriends", "ISteamFriends");
|
||||
_steamUserStatsAccessor = BindInterfaceAccessor<SteamUserStatsAccessorDelegate>("SteamUserStats", "ISteamUserStats");
|
||||
_steamUgcAccessor = BindInterfaceAccessor<SteamUgcAccessorDelegate>("SteamUGC", "ISteamUGC");
|
||||
@@ -2002,7 +1597,6 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
_steamUserStatsSetStatInt32 = Bind<SteamUserStatsSetStatInt32Delegate>("SteamAPI_ISteamUserStats_SetStatInt32");
|
||||
|
||||
// Additional interface accessors requested for broad API coverage.
|
||||
BindAdditionalInterfaceAccessor(InterfaceSteamApps, "SteamApps", "ISteamApps");
|
||||
BindAdditionalInterfaceAccessor(InterfaceSteamController, "SteamController", "ISteamController");
|
||||
BindAdditionalInterfaceAccessor(InterfaceSteamGameCoordinator, "SteamGameCoordinator", "ISteamGameCoordinator");
|
||||
BindAdditionalInterfaceAccessor(InterfaceSteamGameServer, "SteamGameServer", "ISteamGameServer");
|
||||
@@ -2141,38 +1735,13 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
{
|
||||
var libraryName = GetLibraryFileName();
|
||||
var runtimeIdentifier = GetRuntimeIdentifier();
|
||||
var candidates = new List<string>();
|
||||
|
||||
// Paths from SteamManager.ConfigureLibraryPath are tried first, in the order they were added.
|
||||
foreach (var customPath in CustomLibraryPaths)
|
||||
return new[]
|
||||
{
|
||||
var isFile = File.Exists(customPath) ||
|
||||
string.Equals(Path.GetFileName(customPath), libraryName, StringComparison.OrdinalIgnoreCase);
|
||||
candidates.Add(isFile ? customPath : Path.Combine(customPath, libraryName));
|
||||
}
|
||||
|
||||
candidates.Add(Path.Combine(AppContext.BaseDirectory, "runtimes", runtimeIdentifier, "native", libraryName));
|
||||
candidates.Add(Path.Combine(AppContext.BaseDirectory, libraryName));
|
||||
candidates.Add(libraryName);
|
||||
return candidates.ToArray();
|
||||
}
|
||||
|
||||
private static string GetLastLoadError()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()).Message;
|
||||
}
|
||||
|
||||
var errorPtr = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? DlerrorMac() : DlerrorLinux();
|
||||
return errorPtr == IntPtr.Zero ? "unknown error" : Marshal.PtrToStringAnsi(errorPtr) ?? "unknown error";
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e.Message;
|
||||
}
|
||||
Path.Combine(AppContext.BaseDirectory, "runtimes", runtimeIdentifier, "native", libraryName),
|
||||
Path.Combine(AppContext.BaseDirectory, libraryName),
|
||||
libraryName
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetRuntimeIdentifier()
|
||||
@@ -2210,31 +1779,6 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
var appIdValue = appId.ToString();
|
||||
Environment.SetEnvironmentVariable("SteamAppId", appIdValue);
|
||||
Environment.SetEnvironmentVariable("SteamGameId", appIdValue);
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Some runtimes keep Environment.SetEnvironmentVariable managed-only on Unix,
|
||||
// so mirror the values into the native environment that steam_api reads.
|
||||
try
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
SetEnvMac("SteamAppId", appIdValue, 1);
|
||||
SetEnvMac("SteamGameId", appIdValue, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEnvLinux("SteamAppId", appIdValue, 1);
|
||||
SetEnvLinux("SteamGameId", appIdValue, 1);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogDebug(e, "Could not set the native SteamAppId environment variables.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void TryWriteSteamAppIdFile(uint appId)
|
||||
@@ -2312,18 +1856,6 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
[DllImport("libSystem.B.dylib", EntryPoint = "dlsym")]
|
||||
private static extern IntPtr DlsymMac(IntPtr handle, string symbol);
|
||||
|
||||
[DllImport("libdl.so.2", EntryPoint = "dlerror")]
|
||||
private static extern IntPtr DlerrorLinux();
|
||||
|
||||
[DllImport("libSystem.B.dylib", EntryPoint = "dlerror")]
|
||||
private static extern IntPtr DlerrorMac();
|
||||
|
||||
[DllImport("libc.so.6", EntryPoint = "setenv")]
|
||||
private static extern int SetEnvLinux(string name, string value, int overwrite);
|
||||
|
||||
[DllImport("libSystem.B.dylib", EntryPoint = "setenv")]
|
||||
private static extern int SetEnvMac(string name, string value, int overwrite);
|
||||
|
||||
private const int RtldNow = 2;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
using OmegaLeo.HelperLib.Shared.Attributes;
|
||||
|
||||
namespace OmegaLeo.HelperLib.Steamworks
|
||||
{
|
||||
[Documentation(nameof(SteamUgcSubmitItemUpdateResult), "Result of ISteamUGC::SubmitItemUpdate (SubmitItemUpdateResult_t).", null, null)]
|
||||
public sealed class SteamUgcSubmitItemUpdateResult
|
||||
{
|
||||
[Documentation(nameof(Result), "Numeric EResult value (1 = OK).", null, null)]
|
||||
public int Result { get; private set; }
|
||||
|
||||
[Documentation(nameof(UserNeedsToAcceptWorkshopLegalAgreement), "True when the user must accept the Workshop legal agreement before the item becomes visible.", null, null)]
|
||||
public bool UserNeedsToAcceptWorkshopLegalAgreement { get; private set; }
|
||||
|
||||
[Documentation(nameof(PublishedFileId), "The updated Workshop item ID.", null, null)]
|
||||
public ulong PublishedFileId { get; private set; }
|
||||
|
||||
[Documentation(nameof(IoFailure), "True when the result could not be retrieved; the other fields are then not valid.", null, null)]
|
||||
public bool IoFailure { get; private set; }
|
||||
|
||||
[Documentation(nameof(IsSuccess), "True when the result was retrieved and EResult is OK.", null, null)]
|
||||
public bool IsSuccess => !IoFailure && Result == 1;
|
||||
|
||||
internal static SteamUgcSubmitItemUpdateResult FromCallResult(SteamApiCallResult callResult)
|
||||
{
|
||||
// SubmitItemUpdateResult_t { EResult m_eResult; bool m_bUserNeedsToAcceptWorkshopLegalAgreement; PublishedFileId_t m_nPublishedFileId; }
|
||||
// Offsets 0/4/8 under both pack 4 and pack 8.
|
||||
return new SteamUgcSubmitItemUpdateResult
|
||||
{
|
||||
IoFailure = IsFailure(callResult, SteamCallbackIds.SubmitItemUpdateResult, 16),
|
||||
Result = callResult.ReadInt32(0),
|
||||
UserNeedsToAcceptWorkshopLegalAgreement = callResult.ReadBoolean(4),
|
||||
PublishedFileId = callResult.ReadUInt64(8)
|
||||
};
|
||||
}
|
||||
|
||||
internal static bool IsFailure(SteamApiCallResult callResult, int expectedCallbackId, int minimumSize)
|
||||
{
|
||||
return callResult.IoFailure || callResult.CallbackId != expectedCallbackId || callResult.Payload.Length < minimumSize;
|
||||
}
|
||||
}
|
||||
|
||||
[Documentation(nameof(SteamUgcCreateItemResult), "Result of ISteamUGC::CreateItem (CreateItemResult_t).", null, null)]
|
||||
public sealed class SteamUgcCreateItemResult
|
||||
{
|
||||
[Documentation(nameof(Result), "Numeric EResult value (1 = OK).", null, null)]
|
||||
public int Result { get; private set; }
|
||||
|
||||
[Documentation(nameof(PublishedFileId), "The new Workshop item ID. Pass it to StartItemUpdate to upload content.", null, null)]
|
||||
public ulong PublishedFileId { get; private set; }
|
||||
|
||||
[Documentation(nameof(UserNeedsToAcceptWorkshopLegalAgreement), "True when the user must accept the Workshop legal agreement before the item becomes visible.", null, null)]
|
||||
public bool UserNeedsToAcceptWorkshopLegalAgreement { get; private set; }
|
||||
|
||||
[Documentation(nameof(IoFailure), "True when the result could not be retrieved; the other fields are then not valid.", null, null)]
|
||||
public bool IoFailure { get; private set; }
|
||||
|
||||
[Documentation(nameof(IsSuccess), "True when the result was retrieved and EResult is OK.", null, null)]
|
||||
public bool IsSuccess => !IoFailure && Result == 1;
|
||||
|
||||
internal static SteamUgcCreateItemResult FromCallResult(SteamApiCallResult callResult)
|
||||
{
|
||||
// CreateItemResult_t { EResult m_eResult; PublishedFileId_t m_nPublishedFileId; bool m_bUserNeedsToAcceptWorkshopLegalAgreement; }
|
||||
// Pack 8 (Windows): offsets 0/8/16, size 24. Pack 4 (Linux/macOS): offsets 0/4/12, size 16.
|
||||
var large = SteamCallbackDispatcher.UsesLargeCallbackPack;
|
||||
var idOffset = large ? 8 : 4;
|
||||
var legalOffset = large ? 16 : 12;
|
||||
return new SteamUgcCreateItemResult
|
||||
{
|
||||
IoFailure = SteamUgcSubmitItemUpdateResult.IsFailure(callResult, SteamCallbackIds.CreateItemResult, legalOffset + 1),
|
||||
Result = callResult.ReadInt32(0),
|
||||
PublishedFileId = callResult.ReadUInt64(idOffset),
|
||||
UserNeedsToAcceptWorkshopLegalAgreement = callResult.ReadBoolean(legalOffset)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Documentation(nameof(SteamUgcQueryCompletedResult), "Result of ISteamUGC::SendQueryUGCRequest (SteamUGCQueryCompleted_t). Release the query handle with ReleaseQueryUgcRequest when done.", null, null)]
|
||||
public sealed class SteamUgcQueryCompletedResult
|
||||
{
|
||||
[Documentation(nameof(QueryHandle), "The UGC query handle the results belong to.", null, null)]
|
||||
public ulong QueryHandle { get; private set; }
|
||||
|
||||
[Documentation(nameof(Result), "Numeric EResult value (1 = OK).", null, null)]
|
||||
public int Result { get; private set; }
|
||||
|
||||
[Documentation(nameof(NumResultsReturned), "Number of items returned in this page.", null, null)]
|
||||
public uint NumResultsReturned { get; private set; }
|
||||
|
||||
[Documentation(nameof(TotalMatchingResults), "Total number of items matching the query.", null, null)]
|
||||
public uint TotalMatchingResults { get; private set; }
|
||||
|
||||
[Documentation(nameof(CachedData), "True when the results came from the local cache.", null, null)]
|
||||
public bool CachedData { get; private set; }
|
||||
|
||||
[Documentation(nameof(NextCursor), "Cursor for the next page (cursor-based queries only).", null, null)]
|
||||
public string NextCursor { get; private set; } = string.Empty;
|
||||
|
||||
[Documentation(nameof(IoFailure), "True when the result could not be retrieved; the other fields are then not valid.", null, null)]
|
||||
public bool IoFailure { get; private set; }
|
||||
|
||||
[Documentation(nameof(IsSuccess), "True when the result was retrieved and EResult is OK.", null, null)]
|
||||
public bool IsSuccess => !IoFailure && Result == 1;
|
||||
|
||||
internal static SteamUgcQueryCompletedResult FromCallResult(SteamApiCallResult callResult)
|
||||
{
|
||||
// SteamUGCQueryCompleted_t { UGCQueryHandle_t m_handle; EResult m_eResult; uint32 m_unNumResultsReturned;
|
||||
// uint32 m_unTotalMatchingResults; bool m_bCachedData; char m_rgchNextCursor[256]; }
|
||||
// Offsets 0/8/12/16/20/21 under both pack 4 and pack 8.
|
||||
return new SteamUgcQueryCompletedResult
|
||||
{
|
||||
IoFailure = SteamUgcSubmitItemUpdateResult.IsFailure(callResult, SteamCallbackIds.SteamUgcQueryCompleted, 21),
|
||||
QueryHandle = callResult.ReadUInt64(0),
|
||||
Result = callResult.ReadInt32(8),
|
||||
NumResultsReturned = callResult.ReadUInt32(12),
|
||||
TotalMatchingResults = callResult.ReadUInt32(16),
|
||||
CachedData = callResult.ReadBoolean(20),
|
||||
NextCursor = callResult.ReadString(21, 256)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using OmegaLeo.HelperLib.Shared.Attributes;
|
||||
|
||||
namespace OmegaLeo.HelperLib.Steamworks
|
||||
@@ -69,17 +68,6 @@ namespace OmegaLeo.HelperLib.Steamworks
|
||||
{
|
||||
return _ugcManager.UpdateItem(_consumerAppId, _publishedFileId, _options, changeNote, out failedStep);
|
||||
}
|
||||
|
||||
[Documentation(nameof(Submit), "Submits the fluent update session and calls onCompleted with the upload result from SteamManager.Update().", new[]
|
||||
{
|
||||
"changeNote: Changelog note for this update.",
|
||||
"onCompleted: Called once with the upload result.",
|
||||
"failedStep: Name of the failed step if submission returns 0."
|
||||
}, null)]
|
||||
public ulong Submit(string changeNote, Action<SteamUgcSubmitItemUpdateResult> onCompleted, out string failedStep)
|
||||
{
|
||||
return _ugcManager.UpdateItem(_consumerAppId, _publishedFileId, _options, changeNote, onCompleted, out failedStep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OmegaLeo.HelperLib.Shared.Attributes;
|
||||
|
||||
namespace OmegaLeo.HelperLib.Steamworks
|
||||
@@ -117,22 +113,6 @@ var items = ugc.GetSubscribedItems();
|
||||
return submitHandle;
|
||||
}
|
||||
|
||||
[Documentation(nameof(UpdateItem), "Starts an item update, applies option fields, submits it, and calls onCompleted with the upload result from SteamManager.Update().", new[]
|
||||
{
|
||||
"consumerAppId: Your game AppId.",
|
||||
"publishedFileId: Existing workshop item ID.",
|
||||
"options: Options object containing fields to update.",
|
||||
"changeNote: Changelog note for submission.",
|
||||
"onCompleted: Called once with the upload result.",
|
||||
"failedStep: Name of the failed step when the call returns 0."
|
||||
}, null)]
|
||||
public ulong UpdateItem(uint consumerAppId, ulong publishedFileId, SteamUgcItemUpdateOptions options, string changeNote, Action<SteamUgcSubmitItemUpdateResult> onCompleted, out string failedStep)
|
||||
{
|
||||
var submitHandle = UpdateItem(consumerAppId, publishedFileId, options, changeNote, out failedStep);
|
||||
RegisterResult(submitHandle, onCompleted, SteamUgcSubmitItemUpdateResult.FromCallResult, nameof(SubmitItemUpdate));
|
||||
return submitHandle;
|
||||
}
|
||||
|
||||
[Documentation(nameof(CreateItem), "Creates a new Workshop item and returns a Steam API call handle.", new[]
|
||||
{
|
||||
"consumerAppId: Your game AppId.",
|
||||
@@ -143,30 +123,6 @@ var items = ugc.GetSubscribedItems();
|
||||
return SteamNativeApi.CreateItem(consumerAppId, fileType);
|
||||
}
|
||||
|
||||
[Documentation(nameof(CreateItem), "Creates a new Workshop item and calls onCompleted with the CreateItemResult_t from SteamManager.Update(). Returns the Steam API call handle, or 0 on failure.", new[]
|
||||
{
|
||||
"consumerAppId: Your game AppId.",
|
||||
"fileType: Numeric EWorkshopFileType value.",
|
||||
"onCompleted: Called once with the new item ID and result."
|
||||
}, null)]
|
||||
public ulong CreateItem(uint consumerAppId, uint fileType, Action<SteamUgcCreateItemResult> onCompleted)
|
||||
{
|
||||
var apiCall = CreateItem(consumerAppId, fileType);
|
||||
RegisterResult(apiCall, onCompleted, SteamUgcCreateItemResult.FromCallResult, nameof(CreateItem));
|
||||
return apiCall;
|
||||
}
|
||||
|
||||
[Documentation(nameof(CreateItemAsync), "Creates a new Workshop item and returns a task with the CreateItemResult_t. Keep calling SteamManager.Update() while waiting.", new[]
|
||||
{
|
||||
"consumerAppId: Your game AppId.",
|
||||
"fileType: Numeric EWorkshopFileType value.",
|
||||
"cancellationToken: Cancels the wait (the Steam call keeps running)."
|
||||
}, null)]
|
||||
public Task<SteamUgcCreateItemResult> CreateItemAsync(uint consumerAppId, uint fileType, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return AwaitResult(CreateItem(consumerAppId, fileType), SteamUgcCreateItemResult.FromCallResult, nameof(CreateItem), cancellationToken);
|
||||
}
|
||||
|
||||
[Documentation(nameof(StartItemUpdate), "Starts an update transaction for an existing Workshop item.", new[]
|
||||
{
|
||||
"consumerAppId: Your game AppId.",
|
||||
@@ -225,30 +181,6 @@ var items = ugc.GetSubscribedItems();
|
||||
return SteamNativeApi.SubmitItemUpdate(updateHandle, changeNote);
|
||||
}
|
||||
|
||||
[Documentation(nameof(SubmitItemUpdate), "Submits a pending workshop item update and calls onCompleted with the SubmitItemUpdateResult_t from SteamManager.Update(). Returns the Steam API call handle, or 0 when submission failed.", new[]
|
||||
{
|
||||
"updateHandle: Handle from StartItemUpdate.",
|
||||
"changeNote: Changelog note for the update.",
|
||||
"onCompleted: Called once with the upload result."
|
||||
}, null)]
|
||||
public ulong SubmitItemUpdate(ulong updateHandle, string changeNote, Action<SteamUgcSubmitItemUpdateResult> onCompleted)
|
||||
{
|
||||
var apiCall = SubmitItemUpdate(updateHandle, changeNote);
|
||||
RegisterResult(apiCall, onCompleted, SteamUgcSubmitItemUpdateResult.FromCallResult, nameof(SubmitItemUpdate));
|
||||
return apiCall;
|
||||
}
|
||||
|
||||
[Documentation(nameof(SubmitItemUpdateAsync), "Submits a pending workshop item update and returns a task with the SubmitItemUpdateResult_t. Keep calling SteamManager.Update() while waiting.", new[]
|
||||
{
|
||||
"updateHandle: Handle from StartItemUpdate.",
|
||||
"changeNote: Changelog note for the update.",
|
||||
"cancellationToken: Cancels the wait (the upload keeps running)."
|
||||
}, null)]
|
||||
public Task<SteamUgcSubmitItemUpdateResult> SubmitItemUpdateAsync(ulong updateHandle, string changeNote, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return AwaitResult(SubmitItemUpdate(updateHandle, changeNote), SteamUgcSubmitItemUpdateResult.FromCallResult, nameof(SubmitItemUpdate), cancellationToken);
|
||||
}
|
||||
|
||||
[Documentation(nameof(GetItemUpdateProgress), "Gets progress state for a pending item update upload.", new[] { "updateHandle: Handle from StartItemUpdate.", "bytesProcessed: Uploaded bytes output.", "bytesTotal: Total bytes output." }, null)]
|
||||
public uint GetItemUpdateProgress(ulong updateHandle, out ulong bytesProcessed, out ulong bytesTotal)
|
||||
{
|
||||
@@ -274,28 +206,6 @@ var items = ugc.GetSubscribedItems();
|
||||
return SteamNativeApi.SendQueryUgcRequest(queryHandle);
|
||||
}
|
||||
|
||||
[Documentation(nameof(SendQueryUgcRequest), "Submits a UGC query and calls onCompleted with the SteamUGCQueryCompleted_t from SteamManager.Update(). Returns the Steam API call handle, or 0 on failure.", new[]
|
||||
{
|
||||
"queryHandle: UGC query handle returned from CreateQueryAllUgcRequest.",
|
||||
"onCompleted: Called once with the query result."
|
||||
}, null)]
|
||||
public ulong SendQueryUgcRequest(ulong queryHandle, Action<SteamUgcQueryCompletedResult> onCompleted)
|
||||
{
|
||||
var apiCall = SendQueryUgcRequest(queryHandle);
|
||||
RegisterResult(apiCall, onCompleted, SteamUgcQueryCompletedResult.FromCallResult, nameof(SendQueryUgcRequest));
|
||||
return apiCall;
|
||||
}
|
||||
|
||||
[Documentation(nameof(SendQueryUgcRequestAsync), "Submits a UGC query and returns a task with the SteamUGCQueryCompleted_t. Keep calling SteamManager.Update() while waiting.", new[]
|
||||
{
|
||||
"queryHandle: UGC query handle returned from CreateQueryAllUgcRequest.",
|
||||
"cancellationToken: Cancels the wait (the query keeps running)."
|
||||
}, null)]
|
||||
public Task<SteamUgcQueryCompletedResult> SendQueryUgcRequestAsync(ulong queryHandle, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return AwaitResult(SendQueryUgcRequest(queryHandle), SteamUgcQueryCompletedResult.FromCallResult, nameof(SendQueryUgcRequest), cancellationToken);
|
||||
}
|
||||
|
||||
[Documentation(nameof(ReleaseQueryUgcRequest), "Releases a UGC query handle after you are done with query results.", new[] { "queryHandle: UGC query handle to release." }, null)]
|
||||
public bool ReleaseQueryUgcRequest(ulong queryHandle)
|
||||
{
|
||||
@@ -325,30 +235,6 @@ var items = ugc.GetSubscribedItems();
|
||||
{
|
||||
return SteamNativeApi.UnsubscribeItem(publishedFileId);
|
||||
}
|
||||
|
||||
private static void RegisterResult<T>(ulong apiCall, Action<T> onCompleted, Func<SteamApiCallResult, T> convert, string operation)
|
||||
{
|
||||
if (apiCall == 0 || onCompleted == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SteamManager.Dispatcher.RegisterCallResult(apiCall, result => onCompleted(convert(result))))
|
||||
{
|
||||
SteamManager.Logger.LogWarning("{Operation} was submitted but its result will not be delivered because Steam manual callback dispatch is not active.", operation);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<T> AwaitResult<T>(ulong apiCall, Func<SteamApiCallResult, T> convert, string operation, CancellationToken cancellationToken)
|
||||
{
|
||||
if (apiCall == 0)
|
||||
{
|
||||
throw new InvalidOperationException($"{operation} did not return a Steam API call handle. Ensure Steamworks is initialized.");
|
||||
}
|
||||
|
||||
var result = await SteamManager.Dispatcher.WaitForCallResultAsync(apiCall, cancellationToken).ConfigureAwait(false);
|
||||
return convert(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
library.omegaleo.dev
|
||||
@@ -0,0 +1,225 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Changelog Library - OmegaLeo Helper Libraries</title>
|
||||
<link rel="stylesheet" href="../../lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="../../css/site.css%3Fv=AK2YraxbvzgrpO6A1NqAHflCP7fbweSjdyWpd3ERsLE.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header b-pqzonzw7gm>
|
||||
<nav b-pqzonzw7gm class="navbar navbar-expand-sm navbar-dark bg-dark border-bottom box-shadow mb-3">
|
||||
<div b-pqzonzw7gm class="container-fluid">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
OmegaLeo Helper Libraries
|
||||
</a>
|
||||
<button b-pqzonzw7gm class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
|
||||
<span b-pqzonzw7gm class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div b-pqzonzw7gm class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul b-pqzonzw7gm class="navbar-nav flex-grow-1">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="../../index.html">Home</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="core.html">Core</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="changelog.html">Changelog</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="game.html">Game Dev</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="documentation.html">Documentation</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="shared.html">Shared Components</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul b-pqzonzw7gm class="navbar-nav ms-auto">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a b-pqzonzw7gm class="nav-link" href="https://github.com/omegaleo/HelperLib" target="_blank" rel="noopener noreferrer" aria-label="GitHub repository">
|
||||
<i b-pqzonzw7gm class="bi bi-github" style="font-size:1.25rem;"></i> View on Github
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<main b-pqzonzw7gm role="main" class="pb-3">
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="../../index.html">Home</a></li>
|
||||
<li class="breadcrumb-item active">Changelog Library</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="sticky-top" style="top: 20px;">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Changelog Library</h5>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="list-group list-group-flush">
|
||||
<a class="list-group-item list-group-item-action" href="changelog.html#overview">
|
||||
<i class="bi bi-info-circle me-2"></i>Overview
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="changelog.html#namespace-OmegaLeo-HelperLib-Changelog">
|
||||
<i class="bi bi-folder me-2"></i>OmegaLeo.HelperLib.Changelog
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="changelog.html#changelog">
|
||||
<i class="bi bi-clock-history me-2"></i>Changelog
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-9">
|
||||
<div id="overview" class="mb-5">
|
||||
<h2>Changelog Library</h2>
|
||||
<p class="lead">Tools for managing and generating changelogs</p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="namespace-OmegaLeo-HelperLib-Changelog" class="mb-5">
|
||||
<h3>OmegaLeo.HelperLib.Changelog</h3>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">ChangelogHelper</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Changelog</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>ChangelogHelper</code></td>
|
||||
<td><p>Helper class to generate changelog markdown from ChangelogAttributes in the provided Assemblies.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GetChangelogMarkdown</code></td>
|
||||
<td><p>Generates a markdown formatted changelog from the changelog attributes in the provided assemblies.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">ChangelogTool</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Changelog</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>ChangelogTool</code></td>
|
||||
<td><p>Provides methods to extract changelog information from assembly attributes.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ChangelogTool.ExtractChangelog</code></td>
|
||||
<td><p>Extracts changelog entries from the specified assembly.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ChangelogTool.GetMarkdown</code></td>
|
||||
<td><p>Generates a markdown formatted changelog from the assembly's changelog attributes.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="changelog" class="mb-5">
|
||||
<h3>Changelog</h3>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2>Version 1.2.0</h2>
|
||||
<p><strong>OmegaLeo.HelperLib.Changelog.Helpers</strong></p>
|
||||
<ul>
|
||||
<li><strong>ChangelogHelper</strong>:
|
||||
<ul>
|
||||
<li>Created ChangelogHelper to generate markdown from changelog attributes.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Version 1.0.0</h2>
|
||||
<p><strong>OmegaLeo.HelperLib.Changelog.Tools</strong></p>
|
||||
<ul>
|
||||
<li><strong>ChangelogTool</strong>:
|
||||
<ul>
|
||||
<li>Created the class ChangelogTool to extract changelogs via attributes</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sticky-top {
|
||||
max-height: calc(100vh - 40px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #f8f9fa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
|
||||
</main>
|
||||
|
||||
<script src="../../lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../../lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="../../js/site.js%3Fv=y_Ngd8W21UpuCUhEqGbUKDEqFnNfTjAfb24GhJJGUyM"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,924 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Core Library - OmegaLeo Helper Libraries</title>
|
||||
<link rel="stylesheet" href="../../lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="../../css/site.css%3Fv=AK2YraxbvzgrpO6A1NqAHflCP7fbweSjdyWpd3ERsLE.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header b-pqzonzw7gm>
|
||||
<nav b-pqzonzw7gm class="navbar navbar-expand-sm navbar-dark bg-dark border-bottom box-shadow mb-3">
|
||||
<div b-pqzonzw7gm class="container-fluid">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
OmegaLeo Helper Libraries
|
||||
</a>
|
||||
<button b-pqzonzw7gm class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
|
||||
<span b-pqzonzw7gm class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div b-pqzonzw7gm class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul b-pqzonzw7gm class="navbar-nav flex-grow-1">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="../../index.html">Home</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="core.html">Core</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="changelog.html">Changelog</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="game.html">Game Dev</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="documentation.html">Documentation</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="shared.html">Shared Components</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul b-pqzonzw7gm class="navbar-nav ms-auto">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a b-pqzonzw7gm class="nav-link" href="https://github.com/omegaleo/HelperLib" target="_blank" rel="noopener noreferrer" aria-label="GitHub repository">
|
||||
<i b-pqzonzw7gm class="bi bi-github" style="font-size:1.25rem;"></i> View on Github
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<main b-pqzonzw7gm role="main" class="pb-3">
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="../../index.html">Home</a></li>
|
||||
<li class="breadcrumb-item active">Core Library</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="sticky-top" style="top: 20px;">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Core Library</h5>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="list-group list-group-flush">
|
||||
<a class="list-group-item list-group-item-action" href="core.html#overview">
|
||||
<i class="bi bi-info-circle me-2"></i>Overview
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="core.html#namespace-OmegaLeo-HelperLib">
|
||||
<i class="bi bi-folder me-2"></i>OmegaLeo.HelperLib
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="core.html#changelog">
|
||||
<i class="bi bi-clock-history me-2"></i>Changelog
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-9">
|
||||
<div id="overview" class="mb-5">
|
||||
<h2>Core Library</h2>
|
||||
<p class="lead">Core utilities and helper functions for general C# development</p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="namespace-OmegaLeo-HelperLib" class="mb-5">
|
||||
<h3>OmegaLeo.HelperLib</h3>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">ArrayExtensions</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>Array Extensions</code></td>
|
||||
<td><p>Set of extension methods to help with Arrays.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Next</code></td>
|
||||
<td><p>Method to obtain the next object in the array by passing the current index.
|
||||
Note: Idea obtained from TaroDev's video on things to do in Unity - https://youtu.be/Ic5ux-tpkCE?t=302</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">BenchmarkUtility</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>BenchmarkUtility</code></td>
|
||||
<td><p>Utility class for benchmarking code execution time.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
BenchmarkUtility.Start(<span style="color:#D69D85;">"MyBenchmark"</span>);
|
||||
<span style="color:#57A64A;">// Code to benchmark</span>
|
||||
BenchmarkUtility.Stop(<span style="color:#D69D85;">"MyBenchmark"</span>);
|
||||
<span style="color:#569CD6;">var</span> results = BenchmarkUtility.GetResults(<span style="color:#D69D85;">"MyBenchmark"</span>);
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Record</code></td>
|
||||
<td><p>Records the execution time of the provided action and returns the elapsed time in milliseconds.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> time = BenchmarkUtility.Record(() =>
|
||||
{
|
||||
<span style="color:#57A64A;">// Code to benchmark</span>
|
||||
});
|
||||
|
||||
Console.WriteLine($<span style="color:#D69D85;">"Elapsed time: {time} ms"</span>);
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RecordAndSaveToResults</code></td>
|
||||
<td><p>Records the execution time of the provided action, saves it under the given key, and returns the elapsed time in milliseconds.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> time = BenchmarkUtility.RecordAndSaveToResults(<span style="color:#D69D85;">"MyBenchmark"</span>, () =>
|
||||
{
|
||||
<span style="color:#57A64A;">// Code to benchmark</span>
|
||||
});
|
||||
|
||||
Console.WriteLine($<span style="color:#D69D85;">"Elapsed time: {time} ms"</span>);
|
||||
|
||||
<span style="color:#569CD6;">var</span> results = BenchmarkUtility.GetResults(<span style="color:#D69D85;">"MyBenchmark"</span>);
|
||||
|
||||
<span style="color:#569CD6;">var</span> averageTime = results.Average();
|
||||
Console.WriteLine($<span style="color:#D69D85;">"Average time: {averageTime} ms"</span>);
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Start</code></td>
|
||||
<td><p>Starts or restarts the stopwatch for the given key.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Stop</code></td>
|
||||
<td><p>Stops the stopwatch for the given key and records the elapsed time.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GetResults</code></td>
|
||||
<td><p>Retrieves the list of recorded times for the given key.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ClearResults</code></td>
|
||||
<td><p>Clears all recorded benchmark results.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GetAllResults</code></td>
|
||||
<td><p>Retrieves all recorded benchmark results.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">FloatExtensions</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>FloatExtensions</code></td>
|
||||
<td><p>Provides extension methods for the float data type.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Round</code></td>
|
||||
<td><p>Rounds a float value to the specified number of decimal places.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> originalValue = <span style="color:#B5CEA8;">3</span>.14159f;
|
||||
<span style="color:#569CD6;">var</span> roundedValue = originalValue.Round(<span style="color:#B5CEA8;">2</span>); <span style="color:#57A64A;">// roundedValue will be 3.14</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RoundToInt</code></td>
|
||||
<td><p>Rounds a float value to the nearest integer and returns it as an int.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> originalValue = <span style="color:#B5CEA8;">3</span>.14159f;
|
||||
<span style="color:#569CD6;">var</span> roundedValue = originalValue.RoundToInt(); <span style="color:#57A64A;">// roundedValue will be 3</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">IListExtensions</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>IListExtensions</code></td>
|
||||
<td><p>Extension methods for IList<T> to provide additional functionalities such as swapping, replacing, random selection, and shuffling.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Swap</code></td>
|
||||
<td><p>Swaps the elements at the specified indices in the list.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> myList = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">int</span>> { <span style="color:#B5CEA8;">1</span>, <span style="color:#B5CEA8;">2</span>, <span style="color:#B5CEA8;">3</span>, <span style="color:#B5CEA8;">4</span> };
|
||||
myList.Swap(<span style="color:#B5CEA8;">0</span>, <span style="color:#B5CEA8;">2</span>); <span style="color:#57A64A;">// myList is now { 3, 2, 1, 4 }</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Swap</code></td>
|
||||
<td><p>Swaps the elements at the specified indices in the list.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> myList = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">int</span>> { <span style="color:#B5CEA8;">1</span>, <span style="color:#B5CEA8;">2</span>, <span style="color:#B5CEA8;">3</span>, <span style="color:#B5CEA8;">4</span> };
|
||||
myList.Swap(<span style="color:#B5CEA8;">0</span>, <span style="color:#B5CEA8;">2</span>); <span style="color:#57A64A;">// myList is now { 3, 2, 1, 4 }</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Replace</code></td>
|
||||
<td><p>Replaces the first occurrence of a specified value in the list with a new value.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> myList = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">int</span>> { <span style="color:#B5CEA8;">1</span>, <span style="color:#B5CEA8;">2</span>, <span style="color:#B5CEA8;">3</span>, <span style="color:#B5CEA8;">4</span> };
|
||||
myList.Replace(<span style="color:#B5CEA8;">2</span>, <span style="color:#B5CEA8;">5</span>); <span style="color:#57A64A;">// myList is now { 1, 5, 3, 4 }</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Random</code></td>
|
||||
<td><p>Selects a random element from the list.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> myList = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">int</span>> { <span style="color:#B5CEA8;">1</span>, <span style="color:#B5CEA8;">2</span>, <span style="color:#B5CEA8;">3</span>, <span style="color:#B5CEA8;">4</span> };
|
||||
<span style="color:#569CD6;">var</span> randomElement = myList.Random(); <span style="color:#57A64A;">// randomElement could be any of 1, 2, 3, or 4</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Random</code></td>
|
||||
<td><p>Selects a specified number of unique random elements from the list.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> myList = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">int</span>> { <span style="color:#B5CEA8;">1</span>, <span style="color:#B5CEA8;">2</span>, <span style="color:#B5CEA8;">3</span>, <span style="color:#B5CEA8;">4</span> };
|
||||
<span style="color:#569CD6;">var</span> randomElements = myList.Random(<span style="color:#B5CEA8;">2</span>); <span style="color:#57A64A;">// randomElements could be any two of 1, 2, 3, or 4</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Next<T></code></td>
|
||||
<td><p>Method to obtain the next object in the list by passing the current index.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> myList = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">int</span>> { <span style="color:#B5CEA8;">1</span>, <span style="color:#B5CEA8;">2</span>, <span style="color:#B5CEA8;">3</span>,<span style="color:#B5CEA8;">4</span> };
|
||||
<span style="color:#569CD6;">var</span> currentIndex = <span style="color:#B5CEA8;">0</span>;
|
||||
<span style="color:#569CD6;">var</span> nextItem = myList.Next(<span style="color:#569CD6;">ref</span> currentIndex); <span style="color:#57A64A;">// nextItem will be 1, currentIndex will be 1</span>
|
||||
<span style="color:#569CD6;">var</span> nextItem2 = myList.Next(<span style="color:#569CD6;">ref</span> currentIndex); <span style="color:#57A64A;">// nextItem2 will be 2, currentIndex will be 2</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Shuffle<T></code></td>
|
||||
<td><p>Shuffles the elements of the list in place using a cryptographic random number generator.</p>
|
||||
<p>Code obtained from https://stackoverflow.com/a/1262619</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> myList = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">int</span>> { <span style="color:#B5CEA8;">1</span>, <span style="color:#B5CEA8;">2</span>, <span style="color:#B5CEA8;">3</span>, <span style="color:#B5CEA8;">4</span> };
|
||||
myList.Shuffle(); <span style="color:#57A64A;">// myList could now be { 3, 1, 4, 2 } (example output)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">InstancedObject`1</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>InstancedObject<T> Class</code></td>
|
||||
<td><p>A generic base class that ensures only one instance of a derived class exists at any time.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">public</span> <span style="color:#569CD6;">class</span> MySingleton : InstancedObject<MySingleton>
|
||||
{
|
||||
<span style="color:#57A64A;">// Your class implementation here</span>
|
||||
}
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">MathExtensions</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>MathExtensions</code></td>
|
||||
<td><p>Provides extension methods for mathematical operations.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>AverageWithNullValidation</code></td>
|
||||
<td><p>Calculates the average of a list of integers, returning 0 if the list is empty.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> numbers = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">int</span>> { <span style="color:#B5CEA8;">1</span>, <span style="color:#B5CEA8;">2</span>, <span style="color:#B5CEA8;">3</span>, <span style="color:#B5CEA8;">4</span> };
|
||||
<span style="color:#569CD6;">int</span> average = numbers.AverageWithNullValidation(); <span style="color:#57A64A;">// average will be 2 (rounded down)</span>
|
||||
<span style="color:#569CD6;">var</span> emptyList = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">int</span>>();
|
||||
<span style="color:#569CD6;">int</span> averageEmpty = emptyList.AverageWithNullValidation(); <span style="color:#57A64A;">// averageEmpty will be 0</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>AverageWithNullValidation</code></td>
|
||||
<td><p>Calculates the average of a list of doubles, returning 0.0 if the list is empty.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> numbers = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">double</span>> { <span style="color:#B5CEA8;">1</span>.<span style="color:#B5CEA8;">5</span>, <span style="color:#B5CEA8;">2</span>.<span style="color:#B5CEA8;">5</span>, <span style="color:#B5CEA8;">3</span>.<span style="color:#B5CEA8;">5</span> };
|
||||
<span style="color:#569CD6;">double</span> average = numbers.AverageWithNullValidation(); <span style="color:#57A64A;">// average will be 2.5</span>
|
||||
<span style="color:#569CD6;">var</span> emptyList = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">double</span>>();
|
||||
<span style="color:#569CD6;">double</span> averageEmpty = emptyList.AverageWithNullValidation(); <span style="color:#57A64A;">// averageEmpty will be 0.0</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>AverageWithNullValidation</code></td>
|
||||
<td><p>Calculates the average of a list of floats, returning 0.0f if the list is empty.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> numbers = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">float</span>> { <span style="color:#B5CEA8;">1</span>.5f, <span style="color:#B5CEA8;">2</span>.5f, <span style="color:#B5CEA8;">3</span>.5f };
|
||||
<span style="color:#569CD6;">float</span> average = numbers.AverageWithNullValidation(); <span style="color:#57A64A;">// average will be 2.5f</span>
|
||||
<span style="color:#569CD6;">var</span> emptyList = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">float</span>>();
|
||||
<span style="color:#569CD6;">float</span> averageEmpty = emptyList.AverageWithNullValidation(); <span style="color:#57A64A;">// averageEmpty will be 0.0f</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">NeoDictionary`2</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>NeoDictionary</code></td>
|
||||
<td><p>Dictionary like class created to make it easier to display dictionaries in game engines like Unity</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>TryGetValue</code></td>
|
||||
<td><p>Tries to get the value from the NeoDictionary for the given key.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>TryGetValueFromIndex</code></td>
|
||||
<td><p>Tries to get the value from the NeoDictionary at the given index.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Add</code></td>
|
||||
<td><p>Adds a new NeoDictionaryItem to the NeoDictionary.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>AddRange</code></td>
|
||||
<td><p>Adds a range of NeoDictionaryItems from another NeoDictionary to the NeoDictionary.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>AddRange</code></td>
|
||||
<td><p>Adds a range of NeoDictionaryItems to the NeoDictionary.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Any</code></td>
|
||||
<td><p>Checks if the NeoDictionary has any items.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Any</code></td>
|
||||
<td><p>Checks if any item in the NeoDictionary satisfies a condition.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Where</code></td>
|
||||
<td><p>Filters the NeoDictionary items based on a predicate.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>FirstOrDefault</code></td>
|
||||
<td><p>Returns the first item of the NeoDictionary or a default value if the NeoDictionary is empty.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>FirstOrDefault</code></td>
|
||||
<td><p>Returns the first item of the NeoDictionary that satisfies a condition or a default value if no such item is found.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>LastOrDefault</code></td>
|
||||
<td><p>Returns the last item of the NeoDictionary or a default value if the NeoDictionary is empty.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>LastOrDefault</code></td>
|
||||
<td><p>Returns the last item of the NeoDictionary that satisfies a condition or a default value if no such item is found.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Select</code></td>
|
||||
<td><p>Projects each item of the NeoDictionary into a new form.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>IndexOf</code></td>
|
||||
<td><p>Returns the index of the given NeoDictionaryItem.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Remove</code></td>
|
||||
<td><p>Removes the item with the given key.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RemoveAt</code></td>
|
||||
<td><p>Removes the item at the given index.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Replace</code></td>
|
||||
<td><p>Replaces the value for the given key if it exists.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>HasKey</code></td>
|
||||
<td><p>Checks if the NeoDictionary contains the given key.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Clear</code></td>
|
||||
<td><p>Clears all items from the NeoDictionary.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Sort</code></td>
|
||||
<td><p>Sorts the NeoDictionary items using the given comparison.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Count</code></td>
|
||||
<td><p>Returns the number of items in the NeoDictionary.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ForEach</code></td>
|
||||
<td><p>Performs the given action on each item in the NeoDictionary.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ToList</code></td>
|
||||
<td><p>Converts the NeoDictionary items to a List.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Clone</code></td>
|
||||
<td><p>Creates a shallow copy of the NeoDictionary.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Reverse</code></td>
|
||||
<td><p>Reverses the order of the items in the NeoDictionary.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Insert</code></td>
|
||||
<td><p>Inserts an item at the given index.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>InsertRange</code></td>
|
||||
<td><p>Inserts a range of items starting from the given index.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RemoveRange</code></td>
|
||||
<td><p>Removes a range of items starting from the given index.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RemoveAll</code></td>
|
||||
<td><p>Removes all items matching the given predicate.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>FindIndex</code></td>
|
||||
<td><p>Finds the index of the first item matching the given predicate.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Find</code></td>
|
||||
<td><p>Finds the first item matching the given predicate.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>FindAll</code></td>
|
||||
<td><p>Finds all items matching the given predicate.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Merge</code></td>
|
||||
<td><p>Merges another NeoDictionary into this one, ignoring duplicate keys.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ToDictionarySafe</code></td>
|
||||
<td><p>Converts the NeoDictionary to a standard Dictionary while safely handling duplicate keys by ignoring them.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">StringExtensions</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>StringExtensions</code></td>
|
||||
<td><p>Provides extension methods for the string data type.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Truncate</code></td>
|
||||
<td><p>Truncates the string to a specified maximum number of characters, appending '...' if truncation occurs.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> longString = <span style="color:#D69D85;">"This is a very long string that needs to be truncated."</span>;
|
||||
<span style="color:#569CD6;">var</span> truncatedString = longString.Truncate(<span style="color:#B5CEA8;">20</span>); <span style="color:#57A64A;">// truncatedString will be "This is a very long..."</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>IsNullOrEmpty</code></td>
|
||||
<td><p>Checks if the string is null or empty.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">string</span> myString = <span style="color:#D69D85;">""</span>;
|
||||
<span style="color:#569CD6;">bool</span> isNullOrEmpty = myString.IsNullOrEmpty(); <span style="color:#57A64A;">// isNullOrEmpty will be true</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>IsNotNullOrEmpty</code></td>
|
||||
<td><p>Checks if the string is not null or empty.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">string</span> myString = <span style="color:#D69D85;">"Hello"</span>;
|
||||
<span style="color:#569CD6;">bool</span> isNotNullOrEmpty = myString.IsNotNullOrEmpty(); <span style="color:#57A64A;">// isNotNullOrEmpty will be true</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>AnyMatch</code></td>
|
||||
<td><p>Checks if the string matches any of the provided search strings, ignoring case.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">string</span> myString = <span style="color:#D69D85;">"Hello"</span>;
|
||||
<span style="color:#569CD6;">bool</span> matches = myString.AnyMatch(<span style="color:#D69D85;">"hi"</span>, <span style="color:#D69D85;">"hello"</span>, <span style="color:#D69D85;">"greetings"</span>); <span style="color:#57A64A;">// matches will be true</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Reverse</code></td>
|
||||
<td><p>Reverses the characters in the string.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">string</span> myString = <span style="color:#D69D85;">"Hello"</span>;
|
||||
<span style="color:#569CD6;">string</span> reversedString = myString.Reverse(); <span style="color:#57A64A;">// reversedString will be "olleH"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="changelog" class="mb-5">
|
||||
<h3>Changelog</h3>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2>Version 1.2.0</h2>
|
||||
<h3>January 28, 2026</h3>
|
||||
<p><strong>OmegaLeo.HelperLib.Extensions</strong></p>
|
||||
<ul>
|
||||
<li><strong>ArrayExtensions</strong>:
|
||||
<ul>
|
||||
<li>Fixed root namespace to OmegaLeo.HelperLib.Extensions.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>FloatExtensions</strong>:
|
||||
<ul>
|
||||
<li>Fixed root namespace to OmegaLeo.HelperLib.Extensions.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>IListExtensions</strong>:
|
||||
<ul>
|
||||
<li>Fixed root namespace to OmegaLeo.HelperLib.Extensions.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>MathExtensions</strong>:
|
||||
<ul>
|
||||
<li>Fixed root namespace to OmegaLeo.HelperLib.Extensions.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>StringExtensions</strong>:
|
||||
<ul>
|
||||
<li>Fixed root namespace to OmegaLeo.HelperLib.Extensions.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p><strong>OmegaLeo.HelperLib.Helpers</strong></p>
|
||||
<ul>
|
||||
<li><strong>BenchmarkUtility</strong>:
|
||||
<ul>
|
||||
<li>Fixed root namespace to OmegaLeo.HelperLib.Helpers.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p><strong>OmegaLeo.HelperLib.Models</strong></p>
|
||||
<ul>
|
||||
<li><strong>InstancedObject</strong>:
|
||||
<ul>
|
||||
<li>Fixed root namespace to OmegaLeo.HelperLib.Models.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>NeoDictionary</strong>:
|
||||
<ul>
|
||||
<li>Fixed root namespace to OmegaLeo.HelperLib.Models.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sticky-top {
|
||||
max-height: calc(100vh - 40px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #f8f9fa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
|
||||
</main>
|
||||
|
||||
<script src="../../lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../../lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="../../js/site.js%3Fv=y_Ngd8W21UpuCUhEqGbUKDEqFnNfTjAfb24GhJJGUyM"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,187 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Documentation Library - OmegaLeo Helper Libraries</title>
|
||||
<link rel="stylesheet" href="../../lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="../../css/site.css%3Fv=AK2YraxbvzgrpO6A1NqAHflCP7fbweSjdyWpd3ERsLE.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header b-pqzonzw7gm>
|
||||
<nav b-pqzonzw7gm class="navbar navbar-expand-sm navbar-dark bg-dark border-bottom box-shadow mb-3">
|
||||
<div b-pqzonzw7gm class="container-fluid">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
OmegaLeo Helper Libraries
|
||||
</a>
|
||||
<button b-pqzonzw7gm class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
|
||||
<span b-pqzonzw7gm class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div b-pqzonzw7gm class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul b-pqzonzw7gm class="navbar-nav flex-grow-1">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="../../index.html">Home</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="core.html">Core</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="changelog.html">Changelog</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="game.html">Game Dev</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="documentation.html">Documentation</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="shared.html">Shared Components</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul b-pqzonzw7gm class="navbar-nav ms-auto">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a b-pqzonzw7gm class="nav-link" href="https://github.com/omegaleo/HelperLib" target="_blank" rel="noopener noreferrer" aria-label="GitHub repository">
|
||||
<i b-pqzonzw7gm class="bi bi-github" style="font-size:1.25rem;"></i> View on Github
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<main b-pqzonzw7gm role="main" class="pb-3">
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="../../index.html">Home</a></li>
|
||||
<li class="breadcrumb-item active">Documentation Library</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="sticky-top" style="top: 20px;">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Documentation Library</h5>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="list-group list-group-flush">
|
||||
<a class="list-group-item list-group-item-action" href="documentation.html#overview">
|
||||
<i class="bi bi-info-circle me-2"></i>Overview
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="documentation.html#namespace-OmegaLeo-HelperLib-Documentation">
|
||||
<i class="bi bi-folder me-2"></i>OmegaLeo.HelperLib.Documentation
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="documentation.html#changelog">
|
||||
<i class="bi bi-clock-history me-2"></i>Changelog
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-9">
|
||||
<div id="overview" class="mb-5">
|
||||
<h2>Documentation Library</h2>
|
||||
<p class="lead">Tools for generating documentation from code attributes</p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="namespace-OmegaLeo-HelperLib-Documentation" class="mb-5">
|
||||
<h3>OmegaLeo.HelperLib.Documentation</h3>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">DocumentationHelperTool</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Documentation</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>GenerateDocumentation (bool generateForPackageAssembly)</code></td>
|
||||
<td><p>Generates a List of objects of type DocumentationStructure that contain the following fields:<br />
|
||||
<strong>AssemblyName</strong>: Name of the main Assembly, used to identify the root namespace<br />
|
||||
<strong>ClassName</strong>: Name of the class, used to identify the upper level object<br />
|
||||
<strong>Title</strong>: Title what we're generating documentation for<br />
|
||||
<strong>Description</strong>: Description of what we're generating documentation for, this can contain usage examples and can use the args array to pass names(e.g.: This method uses this methodology)<br />
|
||||
<strong>Args</strong>: Array of strings that describe the parameters of the method or class<br />
|
||||
<strong>CodeExample</strong>: A code example of how to use the method or class</p>
|
||||
<p><em>Note: If generateForPackageAssembly is set to true, this will generate documentation for the library as well.</em></p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
DocumentationHelperTool.GenerateDocumentation(<span style="color:#569CD6;">true</span>); <span style="color:#57A64A;">// Generates documentation for all assemblies including the DocumentationHelper.Library package assembly</span>
|
||||
DocumentationHelperTool.GenerateDocumentation(<span style="color:#569CD6;">false</span>); <span style="color:#57A64A;">// Generates documentation for all assemblies excluding the DocumentationHelper.Library package assembly</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="changelog" class="mb-5">
|
||||
<h3>Changelog</h3>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2>Version 1.2.0</h2>
|
||||
<h3>January 26, 2026</h3>
|
||||
<p><strong>OmegaLeo.HelperLib.Documentation.Helpers</strong></p>
|
||||
<ul>
|
||||
<li><strong>DocumentationHelperTool</strong>:
|
||||
<ul>
|
||||
<li>Migrated DocumentationHelper library from NetFlow.DocumentationHelper.Library to it's own package in OmegaLeo.HelperLib</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sticky-top {
|
||||
max-height: calc(100vh - 40px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #f8f9fa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
|
||||
</main>
|
||||
|
||||
<script src="../../lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../../lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="../../js/site.js%3Fv=y_Ngd8W21UpuCUhEqGbUKDEqFnNfTjAfb24GhJJGUyM"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,416 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Game Development Library - OmegaLeo Helper Libraries</title>
|
||||
<link rel="stylesheet" href="../../lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="../../css/site.css%3Fv=AK2YraxbvzgrpO6A1NqAHflCP7fbweSjdyWpd3ERsLE.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header b-pqzonzw7gm>
|
||||
<nav b-pqzonzw7gm class="navbar navbar-expand-sm navbar-dark bg-dark border-bottom box-shadow mb-3">
|
||||
<div b-pqzonzw7gm class="container-fluid">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
OmegaLeo Helper Libraries
|
||||
</a>
|
||||
<button b-pqzonzw7gm class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
|
||||
<span b-pqzonzw7gm class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div b-pqzonzw7gm class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul b-pqzonzw7gm class="navbar-nav flex-grow-1">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="../../index.html">Home</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="core.html">Core</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="changelog.html">Changelog</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="game.html">Game Dev</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="documentation.html">Documentation</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="shared.html">Shared Components</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul b-pqzonzw7gm class="navbar-nav ms-auto">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a b-pqzonzw7gm class="nav-link" href="https://github.com/omegaleo/HelperLib" target="_blank" rel="noopener noreferrer" aria-label="GitHub repository">
|
||||
<i b-pqzonzw7gm class="bi bi-github" style="font-size:1.25rem;"></i> View on Github
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<main b-pqzonzw7gm role="main" class="pb-3">
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="../../index.html">Home</a></li>
|
||||
<li class="breadcrumb-item active">Game Development Library</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="sticky-top" style="top: 20px;">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Game Development Library</h5>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="list-group list-group-flush">
|
||||
<a class="list-group-item list-group-item-action" href="game.html#overview">
|
||||
<i class="bi bi-info-circle me-2"></i>Overview
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="game.html#namespace-OmegaLeo-HelperLib-Game">
|
||||
<i class="bi bi-folder me-2"></i>OmegaLeo.HelperLib.Game
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="game.html#changelog">
|
||||
<i class="bi bi-clock-history me-2"></i>Changelog
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-9">
|
||||
<div id="overview" class="mb-5">
|
||||
<h2>Game Development Library</h2>
|
||||
<p class="lead">Game development utilities for Unity and Godot</p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="namespace-OmegaLeo-HelperLib-Game" class="mb-5">
|
||||
<h3>OmegaLeo.HelperLib.Game</h3>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">CommandConsole</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Game</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>RegisterCommand</code></td>
|
||||
<td><p>Registers a new command with the console.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RegisterCommand</code></td>
|
||||
<td><p>Registers a new command with the console using a delegate.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>UnregisterCommand</code></td>
|
||||
<td><p>Removes a command from the console.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ExecuteCommand</code></td>
|
||||
<td><p>Executes a command string.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Output</code></td>
|
||||
<td><p>Outputs a message to the console.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Error</code></td>
|
||||
<td><p>Outputs an error message to the console.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ClearHistory</code></td>
|
||||
<td><p>Clears command history.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GetAutoComplete</code></td>
|
||||
<td><p>Gets autocomplete suggestions for partial input.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RegisterDefaultCommands</code></td>
|
||||
<td><p>Registers built-in commands.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">DelayedActionHandler</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Game</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>DelayedActionHandler</code></td>
|
||||
<td><p>Handler for managing delayed actions, allowing cancellation and status checking.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> action = <span style="color:#569CD6;">new</span> DelayedAction(...);
|
||||
<span style="color:#569CD6;">var</span> handler = <span style="color:#569CD6;">new</span> DelayedActionHandler(action);
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Cancel</code></td>
|
||||
<td><p>Cancels the delayed action if it has not yet executed.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
handler.Cancel();
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">DelayedActionManager</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Game</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>PendingActionsCount</code></td>
|
||||
<td><p>Gets the count of pending delayed actions.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RunAfter</code></td>
|
||||
<td><p>Schedules an action to run after a specified delay.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RunRepeating</code></td>
|
||||
<td><p>Schedules an action to run repeatedly at specified intervals.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RunAfterCancellable</code></td>
|
||||
<td><p>Schedules an action to run after a delay and returns a handler to cancel it if needed.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>CancelAll</code></td>
|
||||
<td><p>Cancels all pending delayed actions.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">ListExtensions</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Game</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>Shuffle</code></td>
|
||||
<td><p>Shuffles the elements of the list in place using the provided RandomNumberGenerator.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
<span style="color:#569CD6;">var</span> list = <span style="color:#569CD6;">new</span> List<<span style="color:#569CD6;">int</span>> { <span style="color:#B5CEA8;">1</span>, <span style="color:#B5CEA8;">2</span>, <span style="color:#B5CEA8;">3</span>, <span style="color:#B5CEA8;">4</span>};
|
||||
<span style="color:#569CD6;">var</span> rng = <span style="color:#569CD6;">new</span> RandomNumberGenerator();
|
||||
<span style="color:#57A64A;">// List before: [1, 2, 3, 4]</span>
|
||||
list.Shuffle(rng);
|
||||
<span style="color:#57A64A;">// List after: [3, 1, 4, 2] (example output)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">SaveManager</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Game</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>Save</code></td>
|
||||
<td><p>Saves data to a JSON file.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Load</code></td>
|
||||
<td><p>Loads data from a JSON file.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>TryLoad</code></td>
|
||||
<td><p>Attempts to load data from a JSON file, returning a success flag.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>SaveExists</code></td>
|
||||
<td><p>Checks if a save file exists.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>DeleteSave</code></td>
|
||||
<td><p>Deletes a save file.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GetAllSaveFiles</code></td>
|
||||
<td><p>Retrieves all save files in the save directory.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">WeightedPicker</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Game</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>WeightedPicker.Pick</code></td>
|
||||
<td><p>Picks a random item from a dictionary of items with associated weights.</p>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sticky-top {
|
||||
max-height: calc(100vh - 40px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #f8f9fa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
|
||||
</main>
|
||||
|
||||
<script src="../../lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../../lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="../../js/site.js%3Fv=y_Ngd8W21UpuCUhEqGbUKDEqFnNfTjAfb24GhJJGUyM"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,235 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Shared Library - OmegaLeo Helper Libraries</title>
|
||||
<link rel="stylesheet" href="../../lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="../../css/site.css%3Fv=AK2YraxbvzgrpO6A1NqAHflCP7fbweSjdyWpd3ERsLE.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header b-pqzonzw7gm>
|
||||
<nav b-pqzonzw7gm class="navbar navbar-expand-sm navbar-dark bg-dark border-bottom box-shadow mb-3">
|
||||
<div b-pqzonzw7gm class="container-fluid">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
OmegaLeo Helper Libraries
|
||||
</a>
|
||||
<button b-pqzonzw7gm class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
|
||||
<span b-pqzonzw7gm class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div b-pqzonzw7gm class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul b-pqzonzw7gm class="navbar-nav flex-grow-1">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="../../index.html">Home</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="core.html">Core</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="changelog.html">Changelog</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="game.html">Game Dev</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="documentation.html">Documentation</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="shared.html">Shared Components</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul b-pqzonzw7gm class="navbar-nav ms-auto">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a b-pqzonzw7gm class="nav-link" href="https://github.com/omegaleo/HelperLib" target="_blank" rel="noopener noreferrer" aria-label="GitHub repository">
|
||||
<i b-pqzonzw7gm class="bi bi-github" style="font-size:1.25rem;"></i> View on Github
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<main b-pqzonzw7gm role="main" class="pb-3">
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="../../index.html">Home</a></li>
|
||||
<li class="breadcrumb-item active">Shared Library</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="sticky-top" style="top: 20px;">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Shared Library</h5>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="list-group list-group-flush">
|
||||
<a class="list-group-item list-group-item-action" href="shared.html#overview">
|
||||
<i class="bi bi-info-circle me-2"></i>Overview
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="shared.html#namespace-OmegaLeo-HelperLib-Shared">
|
||||
<i class="bi bi-folder me-2"></i>OmegaLeo.HelperLib.Shared
|
||||
</a>
|
||||
<a class="list-group-item list-group-item-action" href="shared.html#changelog">
|
||||
<i class="bi bi-clock-history me-2"></i>Changelog
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-9">
|
||||
<div id="overview" class="mb-5">
|
||||
<h2>Shared Library</h2>
|
||||
<p class="lead">Library of shared attributes and utilities used across other OmegaLeo.HelperLib packages</p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div id="namespace-OmegaLeo-HelperLib-Shared" class="mb-5">
|
||||
<h3>OmegaLeo.HelperLib.Shared</h3>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">ChangelogAttribute</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Shared</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>ChangelogAttribute</code></td>
|
||||
<td><p>Attribute to annotate classes, methods, or properties with changelog information.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
[Changelog(<span style="color:#D69D85;">"1.0.0"</span>, <span style="color:#D69D85;">"Created ChangelogAttribute to be used to register changes in the code."</span>)]
|
||||
<span style="color:#569CD6;">public</span> <span style="color:#569CD6;">class</span> ChangelogAttribute : Attribute
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">DocumentationAttribute</h4>
|
||||
<small class="text-muted">OmegaLeo.HelperLib.Shared</small>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Member</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>DocumentationAttribute</code></td>
|
||||
<td><p>Attribute to annotate classes, methods, or properties with documentation information.</p>
|
||||
<br/>
|
||||
<strong>Example:</strong><br/>
|
||||
<div class="example-code mb-2">
|
||||
<div style="color:#DADADA;background-color:#1E1E1E;"><pre>
|
||||
[Documentation(
|
||||
<span style="color:#D69D85;">"MyMethod"</span>,
|
||||
<span style="color:#D69D85;">"This method does something important."</span>,
|
||||
<span style="color:#569CD6;">new</span> <span style="color:#569CD6;">string</span>[] { <span style="color:#D69D85;">"param1: The first parameter."</span>, <span style="color:#D69D85;">"param2: The second parameter."</span> },
|
||||
<span style="color:#D69D85;">"MyMethod(param1, param2);"</span>
|
||||
)]
|
||||
<span style="color:#569CD6;">public</span> <span style="color:#569CD6;">void</span> MyMethod(<span style="color:#569CD6;">string</span> param1, <span style="color:#569CD6;">int</span> param2)
|
||||
{
|
||||
<span style="color:#57A64A;">// Method implementation</span>
|
||||
}
|
||||
</pre></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="changelog" class="mb-5">
|
||||
<h3>Changelog</h3>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2>Version 1.2.1</h2>
|
||||
<h3>January 28, 2026</h3>
|
||||
<p><strong>OmegaLeo.HelperLib.Shared.Attributes</strong></p>
|
||||
<ul>
|
||||
<li><strong>ChangelogAttribute</strong>:
|
||||
<ul>
|
||||
<li>Created documentation for ChangelogAttribute.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>DocumentationAttribute</strong>:
|
||||
<ul>
|
||||
<li>Created documentation for DocumentationAttribute.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Version 1.0.0</h2>
|
||||
<p><strong>OmegaLeo.HelperLib.Shared.Attributes</strong></p>
|
||||
<ul>
|
||||
<li><strong>ChangelogAttribute</strong>:
|
||||
<ul>
|
||||
<li>Created ChangelogAttribute to be used to register changes in the code.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sticky-top {
|
||||
max-height: calc(100vh - 40px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #f8f9fa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
|
||||
</main>
|
||||
|
||||
<script src="../../lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="../../lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="../../js/site.js%3Fv=y_Ngd8W21UpuCUhEqGbUKDEqFnNfTjAfb24GhJJGUyM"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,40 @@
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
|
||||
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
|
||||
}
|
||||
|
||||
html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
padding: 1rem;
|
||||
background-color: #495057;
|
||||
position: relative;
|
||||
|
||||
color: #f2f2f2;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.example-code > div {
|
||||
border-radius: 0.5rem !important;
|
||||
background-color: #495057 !important;
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>OmegaLeo Helper Libraries - OmegaLeo Helper Libraries</title>
|
||||
<link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="css/site.css%3Fv=AK2YraxbvzgrpO6A1NqAHflCP7fbweSjdyWpd3ERsLE.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header b-pqzonzw7gm>
|
||||
<nav b-pqzonzw7gm class="navbar navbar-expand-sm navbar-dark bg-dark border-bottom box-shadow mb-3">
|
||||
<div b-pqzonzw7gm class="container-fluid">
|
||||
<a class="navbar-brand" href="index.html">
|
||||
OmegaLeo Helper Libraries
|
||||
</a>
|
||||
<button b-pqzonzw7gm class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse">
|
||||
<span b-pqzonzw7gm class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div b-pqzonzw7gm class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul b-pqzonzw7gm class="navbar-nav flex-grow-1">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="index.html">Home</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="Home/Library/core.html">Core</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="Home/Library/changelog.html">Changelog</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="Home/Library/game.html">Game Dev</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="Home/Library/documentation.html">Documentation</a>
|
||||
</li>
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a class="nav-link" href="Home/Library/shared.html">Shared Components</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul b-pqzonzw7gm class="navbar-nav ms-auto">
|
||||
<li b-pqzonzw7gm class="nav-item">
|
||||
<a b-pqzonzw7gm class="nav-link" href="https://github.com/omegaleo/HelperLib" target="_blank" rel="noopener noreferrer" aria-label="GitHub repository">
|
||||
<i b-pqzonzw7gm class="bi bi-github" style="font-size:1.25rem;"></i> View on Github
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<main b-pqzonzw7gm role="main" class="pb-3">
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="text-center mb-5">
|
||||
<h1 class="display-4">OmegaLeo Helper Libraries</h1>
|
||||
<p class="lead">Comprehensive C# libraries for game development and general utilities</p>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Core Library</h5>
|
||||
<p class="card-text">Core utilities and helper functions for general C# development</p>
|
||||
<p class="text-muted small">
|
||||
8 classes documented
|
||||
</p>
|
||||
<a href="https://www.nuget.org/packages/OmegaLeo.HelperLib"
|
||||
target="_blank"
|
||||
class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-box-seam"></i> View on NuGet
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a class="btn btn-primary w-100" href="Home/Library/core.html">
|
||||
View Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Changelog Library</h5>
|
||||
<p class="card-text">Tools for managing and generating changelogs</p>
|
||||
<p class="text-muted small">
|
||||
2 classes documented
|
||||
</p>
|
||||
<a href="https://www.nuget.org/packages/OmegaLeo.HelperLib.Changelog"
|
||||
target="_blank"
|
||||
class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-box-seam"></i> View on NuGet
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a class="btn btn-primary w-100" href="Home/Library/changelog.html">
|
||||
View Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Game Development Library</h5>
|
||||
<p class="card-text">Game development utilities for Unity and Godot</p>
|
||||
<p class="text-muted small">
|
||||
6 classes documented
|
||||
</p>
|
||||
<a href="https://www.nuget.org/packages/OmegaLeo.HelperLib.Game"
|
||||
target="_blank"
|
||||
class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-box-seam"></i> View on NuGet
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a class="btn btn-primary w-100" href="Home/Library/game.html">
|
||||
View Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Documentation Library</h5>
|
||||
<p class="card-text">Tools for generating documentation from code attributes</p>
|
||||
<p class="text-muted small">
|
||||
1 classes documented
|
||||
</p>
|
||||
<a href="https://www.nuget.org/packages/OmegaLeo.HelperLib.Documentation"
|
||||
target="_blank"
|
||||
class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-box-seam"></i> View on NuGet
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a class="btn btn-primary w-100" href="Home/Library/documentation.html">
|
||||
View Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Shared Library</h5>
|
||||
<p class="card-text">Library of shared attributes and utilities used across other OmegaLeo.HelperLib packages</p>
|
||||
<p class="text-muted small">
|
||||
2 classes documented
|
||||
</p>
|
||||
<a href="https://www.nuget.org/packages/OmegaLeo.HelperLib.Shared"
|
||||
target="_blank"
|
||||
class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-box-seam"></i> View on NuGet
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a class="btn btn-primary w-100" href="Home/Library/shared.html">
|
||||
View Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/site.js%3Fv=y_Ngd8W21UpuCUhEqGbUKDEqFnNfTjAfb24GhJJGUyM"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,4 @@
|
||||
// Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
|
||||
// for details on configuring this project to bundle and minify static web assets.
|
||||
|
||||
// Write your JavaScript code.
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+2
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user