This commit is contained in:
2026-10-06 16:26:20 +05:30
parent d4c7f5dd46
commit 7fa0621ff8
230 changed files with 16821 additions and 55 deletions
@@ -0,0 +1,155 @@
#if UNITY_EDITOR
using System.IO;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Build;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEngine;
public static class OtaAddressablesSetup
{
const string RemoteLoadUrl = "https://kkapi.playpoolstudios.com/ota/[BuildTarget]";
const string GameContentLabel = "game-content";
const string BootstrapScenePath = "Assets/Scenes/Bootstrap.unity";
static readonly string[] RemoteScenePaths =
{
"Assets/Scenes/Intro.unity",
"Assets/Scenes/MainMenu.unity",
"Assets/Scenes/Game.unity"
};
[MenuItem("Tools/OTA/Configure Addressables")]
public static void Configure()
{
AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.GetSettings(true);
settings.BuildRemoteCatalog = true;
settings.DisableCatalogUpdateOnStartup = true;
settings.OverridePlayerVersion = "";
string profileId = settings.activeProfileId;
settings.profileSettings.SetValue(profileId, AddressableAssetSettings.kRemoteBuildPath, "ServerData/[BuildTarget]");
settings.profileSettings.SetValue(profileId, AddressableAssetSettings.kRemoteLoadPath, RemoteLoadUrl);
settings.RemoteCatalogBuildPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteBuildPath);
settings.RemoteCatalogLoadPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteLoadPath);
for (int i = 0; i < settings.DataBuilders.Count; i++)
{
if (settings.GetDataBuilder(i) != null && settings.GetDataBuilder(i).Name.Contains("Asset Database"))
{
settings.ActivePlayModeDataBuilderIndex = i;
break;
}
}
AddressableAssetGroup local = GetOrCreateGroup(settings, "Local_Bootstrap");
AddressableAssetGroup remote = GetOrCreateGroup(settings, "Remote_Game");
ConfigureGroup(settings, local, true);
ConfigureGroup(settings, remote, false);
MarkScene(settings, local, BootstrapScenePath, "Bootstrap", false);
for (int i = 0; i < RemoteScenePaths.Length; i++)
{
string path = RemoteScenePaths[i];
string address = Path.GetFileNameWithoutExtension(path);
MarkScene(settings, remote, path, address, true);
}
settings.SetDirty(AddressableAssetSettings.ModificationEvent.BatchModification, null, true, true);
AssetDatabase.SaveAssets();
var scenes = new EditorBuildSettingsScene[1];
scenes[0] = new EditorBuildSettingsScene(BootstrapScenePath, true);
EditorBuildSettings.scenes = scenes;
Debug.Log("OTA Addressables configured. Remote load path: " + RemoteLoadUrl);
}
[MenuItem("Tools/OTA/Build Content")]
public static void BuildContent()
{
Configure();
AddressableAssetSettings.BuildPlayerContent(out AddressablesPlayerBuildResult result);
if (!string.IsNullOrEmpty(result.Error))
{
Debug.LogError("OTA content build failed: " + result.Error);
return;
}
string statePath = ContentUpdateScript.GetContentStateDataPath(false);
Debug.Log("OTA content build finished. Keep this file for later patches: " + statePath);
}
[MenuItem("Tools/OTA/Build Content Update")]
public static void BuildContentUpdate()
{
AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
Debug.LogError("Addressables settings are missing. Run Tools/OTA/Configure Addressables first.");
return;
}
string statePath = ContentUpdateScript.GetContentStateDataPath(false);
if (!File.Exists(statePath))
{
Debug.LogError("Missing content state at " + statePath + ". Run Tools/OTA/Build Content from the player build you shipped.");
return;
}
ContentUpdateScript.BuildContentUpdate(settings, statePath);
Debug.Log("OTA content update built. Upload ServerData and keep " + statePath);
}
static AddressableAssetGroup GetOrCreateGroup(AddressableAssetSettings settings, string name)
{
AddressableAssetGroup group = settings.FindGroup(name);
if (group != null)
return group;
return settings.CreateGroup(name, false, false, false, null, typeof(BundledAssetGroupSchema), typeof(ContentUpdateGroupSchema));
}
static void ConfigureGroup(AddressableAssetSettings settings, AddressableAssetGroup group, bool local)
{
BundledAssetGroupSchema bundle = group.GetSchema<BundledAssetGroupSchema>();
if (bundle == null)
bundle = group.AddSchema<BundledAssetGroupSchema>();
if (local)
{
bundle.BuildPath.SetVariableByName(settings, AddressableAssetSettings.kLocalBuildPath);
bundle.LoadPath.SetVariableByName(settings, AddressableAssetSettings.kLocalLoadPath);
}
else
{
bundle.BuildPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteBuildPath);
bundle.LoadPath.SetVariableByName(settings, AddressableAssetSettings.kRemoteLoadPath);
}
bundle.BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackTogether;
bundle.UseAssetBundleCrc = true;
bundle.UseAssetBundleCache = true;
ContentUpdateGroupSchema update = group.GetSchema<ContentUpdateGroupSchema>();
if (update == null)
update = group.AddSchema<ContentUpdateGroupSchema>();
update.StaticContent = local;
}
static void MarkScene(AddressableAssetSettings settings, AddressableAssetGroup group, string assetPath, string address, bool gameContent)
{
string guid = AssetDatabase.AssetPathToGUID(assetPath);
if (string.IsNullOrEmpty(guid))
{
Debug.LogWarning("OTA scene missing, skipped: " + assetPath);
return;
}
AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, group, false, false);
entry.address = address;
if (gameContent)
entry.SetLabel(GameContentLabel, true, true, true);
}
}
#endif