ConcentricContent
Asynchronous content creation library
模組介紹 作者原文
Concentric Content
A library for simplifying asset creation, for big content mods.
As simple as adding to your solution and implementing the required interfaces. Check the Kamunagi of Chains character for an example on nearly every type of use-case. You can also ping me, Nines @unit_9_type_s with any questions and I will try my best to answer them!
The example below would be for a monolithic file involving a skill, a projectile, and a visual effect.
public class SkillNameState: BaseState
{
public static GameObject MuzzlePrefab;
public static GameObject ProjectilePrefab; //explained below
public override void OnEnter()
{
//whatever kinda stuff
}
}
public class SkillName: Concentric, IEffect, IProjectile, IProjectileGhost, ISkill
{
public override async Task Initialize()
{
//explained below
}
async Task IProjectile.BuildObject()
{
var projectile = (await LoadAsset("RoR2/DLC2/Seeker/SpiritPunchProjectile.prefab"))!.InstantiateClone("CustomSeekerPrimary", true)
projectile.GetComponent().ghostPrefab = await this.GetProjectileGhost();
return projectile; //NOTE LoadAsset will not work unless you read further down below
}
async Task IProjectileGhost.BuildObject()
{
var ghost = (await LoadAsset("RoR2/Base/Grandparent/GrandparentBoulderGhost.prefab"))!.InstantiateClone("BoulderProjectileGhost", false);
ghost.transform.localScale = Vector3.one * 0.3f;
return ghost;
}
async Task ISkill.BuildObject()
{
var skill = ScriptableObject.CreateInstance();
skill.skillName = "Primary 1";
skill.skillNameToken = KamunagiAsset.tokenPrefix + "PRIMARY1_NAME";
skill.skillDescriptionToken = KamunagiAsset.tokenPrefix + "PRIMARY1_DESCRIPTION";
skill.activationState = new SerializableEntityStateType(typeof(SkillName));
skill.icon = await LoadAsset("AssetBundleName:FileName"); //NOTE LoadAsset will not work unless you read further down below
skill.activationStateMachineName = "Weapon";
skill.baseRechargeInterval = 6f;
skill.beginSkillCooldownOnSkillEnd = true;
skill.interruptPriority = InterruptPriority.Any;
return skill;
}
async Task IEffect.BuildOject()
{
var effect = await LoadAsset("AssetBundleName:FileName"); //NOTE LoadAsset will not work unless you read further down below
effect.AddComponent().baseScale = Vector3.one * 3f;
return effect;
}
IEnumerable ISkill.GetEntityStates() => new { typeof(SkillNameState) };
}
Using the assets in your EntityStates:
You can field them and then intialize them in your Concentric class, like this:
public override async Task Initialize()
{
await base.Initialize();
SkillNameState.MuzzlePrefab = await this.GetEffect();
SkillNameState.ProjectilePrefab = await this.GetProjectile();
}
LoadAsset won't actually work unless you have this in your MainPlugin.cs
public static Task LoadAsset(string assetPath) where T: UnityEngine.Object
{
if (assetPath.StartsWith("addressable:"))
{
return Addressables.LoadAssetAsync(assetPath["addressable:".Length..]).Task;
}
if (assetPath.StartsWith("legacy:"))
{
return LegacyResourcesAPI.LoadAsync(assetPath["legacy:".Length..]).Task;
}
var colinIndex = assetPath.IndexOf(":", StringComparison.Ordinal);
if (colinIndex (assetPath).Task;
var source = new TaskCompletionSource();
var handle = bundles[assetPath[..colinIndex]].LoadAssetAsync(assetPath[(colinIndex + 1)..]);
handle.completed += _ => source.SetResult((T)handle.asset);
return source.Task;
}
Credits
- Bubbet, did the entire thing
- Nines, ground-zero testing, wrote Readme, also named the library.
Changelog
1.0.1
-Fixed a bug that caused Captain's beacons to not show up in the lobby
1.0.0
- Initial Release
安裝與使用 安裝:BepInEx 外掛
- 本站下載的壓縮包就是模組本體,通常是 BepInEx 外掛(解壓後得到 .dll 或外掛資料夾)。
- 建議流程:用社群模組管理器(如 r2modman)選中本遊戲後匯入該模組,管理器會自動裝好 BepInEx 前置並處理依賴。
- 手動流程:先在遊戲目錄裝好 BepInEx 載入器,再把解壓出的 .dll 或外掛資料夾放進 BepInEx/plugins/。
- 啟動遊戲,BepInEx 控制台會列印載入日誌;確認這個模組出現在日誌裡即為安裝成功。
帶「前置依賴」的模組需要一併安裝,否則不會載入。功能開關通常在遊戲內或外掛自帶的設定檔裡調整。
下面這些內容需要先安裝,否則該模組不會生效: