EA 23.343 Nightly โ
September 5, 2026
13 files modified.
Important Changes โ
Possible breaking changes. Click the filename to view the chunk.
LayerMod (1) โ
private void Move(BaseModPackage p, ItemMod b, int a)
private void Move(BaseModPackage p, int a) ModManager (4) โ
public IEnumerator LoadWorkshopPackages()
public void InitPackagesMeta() private IEnumerator UpdateWorkshopPackages()
private string UnmetDependency(BaseModPackage p, Dictionary<string, BaseModPackage> loaded, Dictionary<string, BaseModPackage> installed) public void InitPackagesMeta()
private static void RegisterLoaded(BaseModPackage p, Dictionary<string, BaseModPackage> loaded, Dictionary<string, BaseModPackage> claimed) public void ActivatePackages()
private IEnumerator QuerySubscriptions(PublishedFileId_t[] subscribed) ActEffect โ
void AddCon<T>(int rate, int p2) where T : Condition
{
num14 = num15;
}
Debug.Log(num14);
if (EClass.rnd(100) > num14)
{
TC.Say("debuff_resist", TC);Card โ
{
return this;
}
if (!isScaled && flag && LV >= 50)
if (LV >= Mathf.Max(50, sourceCard.LV))
{
isScaled = true;
}Chara โ
public override string GetName(NameStyle style, int num = -1)
{
num2 = 1;
}
text = (Aka.IsEmpty() ? text.Bracket(num2) : (num2 switch
text = ((Aka.IsEmpty() || !(Aka != text)) ? text.Bracket(num2) : (num2 switch
{
-1 => "_aka",
1 => "_aka3", {
preventRegen = true;
}
if (!preventRegen)
if (preventRegen)
{
if (EClass.rnd(25) == 0 && base.hp < MaxHP)
{
HealHP(EClass.rnd(Evalue(300) / 3 + 1) + 1);
elements.ModExp(300, 8f);
}
if (EClass.rnd(8) == 0 && mana.value < mana.max)
{
mana.Mod(EClass.rnd(Evalue(301) / 2 + 1) + 1);
elements.ModExp(301, 8f);
}
if (EClass.rnd(20) == 0 && !IsPC && stamina.value < stamina.max)
return;
}
if (EClass.rnd(25) == 0 && base.hp < MaxHP)
{
HealHP(EClass.rnd(Evalue(300) / 3 + 1) + 1);
elements.ModExp(300, 8f);
}
if (EClass.rnd(8) == 0 && mana.value < mana.max)
{
mana.Mod(EClass.rnd(Evalue(301) / 2 + 1) + 1);
elements.ModExp(301, 8f);
}
if (EClass.rnd(20) != 0)
{
return;
}
if (IsPC)
{
if (EClass.player.staminaRecovery > 0)
{
stamina.Mod(EClass.rnd(5) + 1);
EClass.player.RecoverStamina(Evalue(62) / 100 + ((Evalue(62) % 100 > EClass.rnd(100)) ? 1 : 0));
}
}
else if (stamina.value < stamina.max)
{
stamina.Mod(EClass.rnd(5) + 1);
}
}
public void SyncRide()public override void Die(Element e = null, Card origin = null, AttackSource attaโฆ)
}
if (IsPC)
{
EClass.player.staminaRecovery = 0;
EClass._zone.isDeathLocation = true;
string s = ((origin == null) ? text : "dead_by");
Msg.thirdPerson1.Set(EClass.pc);public bool UseAbility(Act a, Card tc = null, Point pos = null, bool pt = false)
elements.ModExp(304, Mathf.Clamp(num6 * 2, 1, 200));
break;
case Act.CostType.SP:
{
int value = stamina.value;
stamina.Mod(-num6);
if (IsPC && a.HasTag("recovery"))
{
EClass.player.staminaRecovery += value - stamina.value;
}
ignoreSPAbsorb = true;
break;
}
}
if (a is Spell && GetCondition<ConSilence>() != null)
{
Say("cast_silence", this);public Condition AddCondition(Condition c, bool force = false)
Element defenseAttribute = c.GetDefenseAttribute(this);
if (defenseAttribute != null)
{
c.power = 100 * c.power / Mathf.Max(100 + defenseAttribute.Value, 1);
c.power = MathEx.ClampToInt(100L * (long)c.power / Mathf.Max(100 + defenseAttribute.Value, 1));
}
if (c.source.resistance.Length != 0)
{public void OnSleep(int power, int days = 1, bool isSunLit = false)
}
if (IsPC)
{
EClass.player.RecoverStamina(EClass.player.staminaRecovery);
foreach (BodySlot slot in body.slots)
{
if (slot.thing != null)
if (slot.thing != null && slot.thing.GetBool(135))
{
LayerInventory.SetDirty(slot.thing);
slot.thing.SetBool(135, enable: false);
}
}CharaBody โ
public bool Equip(Thing thing, BodySlot slot = null, bool msg = true)
thing.c_DNA.Apply(owner, reverse: false);
Msg.Say("equip_relic");
owner.feat -= thing.c_DNA.cost;
if (!EClass.debug.enable)
if (!EClass.debug.godMode)
{
thing.SetBool(135, enable: true);
}ELEMENT โ
public void _WriteNote(UINote n, Chara c, Act act)
{
n.AddText("_bullet".lang() + "hintSyncRide".lang());
}
if (EClass.pc.HasElement(1274) && source.tag.Contains("dontForget"))
if (source.tag.Contains("recovery"))
{
n.AddText("_bullet".lang() + "hintStaminaRecovery".lang());
}
if (source.tag.Contains("dontForget"))
{
n.AddText("_bullet".lang() + "hintDontForget".lang());
}ElinGameIOPropertyAttribute โ
public override void Register(PropertyInfo property)
}
MethodInfo getMethod = property.GetMethod;
MethodInfo setMethod = property.SetMethod;
if (!(getMethod == null) && !(setMethod == null) && setMethod.IsStatic)
if (!(getMethod == null) && !(setMethod == null) && getMethod.IsStatic && setMethod.IsStatic)
{
Func<object> item = getMethod.CreateDelegate<Func<object>>();
Func<object> item = CreateGetterDelegate(getMethod);
Action<object> item2 = CreateSetterDelegate(setMethod);
Type declaringType = property.DeclaringType;
_contextVars[declaringType.FullName + ":" + ChunkName] = (property, item, item2);
}
}
private static Func<object> CreateGetterDelegate(MethodInfo method)
{
return Expression.Lambda<Func<object>>(Expression.Convert(Expression.Call(method), typeof(object)), Array.Empty<ParameterExpression>()).Compile();
}
private static Action<object> CreateSetterDelegate(MethodInfo method)
{
Type parameterType = method.GetParameters()[0].ParameterType;private static void LoadGameIOProperty(GameIOContext context)
}
static object CoerceValue(object obj, Type type)
{
if (obj == null)
{
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
if (obj is JToken jToken)
{
return jToken.ToObject(type);
}
if (type.IsInstanceOfType(obj))
{
return obj;
}
if (obj is IConvertible)
if (obj == null)
{
return Convert.ChangeType(obj, type);
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
return obj;
object result;
return DynamicReflection.TryCoerce(obj, type, out result) ? result : obj;
}
}LayerMod โ
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using HeathenEngineering.SteamworksIntegration;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class LayerMod : ELayer
{
private sealed class PreviewEntry
{
public Sprite sprite;
public bool ownsTexture;
public ModPreview.PreviewType kind;
}
private sealed class HoverRelay : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler
{
public Action onEnter;
public void OnPointerEnter(PointerEventData eventData)
{
onEnter?.Invoke();
}
}
private const float previewBoxHeight = 240f;
private const string urlWorkshopItem = "https://steamcommunity.com/sharedfiles/filedetails/?id=";
public static LayerMod Instance;
public UIList list;public class LayerMod : ELayer
public UIText textRestart;
public UIText textNoResult;
public UIButton toggleDisableMods;
public UIButton buttonClearSearch;
public InputField inputSearch;
public UIScrollView panelScroll;
public UIHeader panelHeader;
public UINote panelNote;
private UIButton buttonFilter;
private BaseModPackage panelTarget;
private float timerSearch;
private bool wasSearchFocused;
private string lastSearch = "";
private string[] searchTerms = Array.Empty<string>();
private ModSearch.Filter filterMode;
private readonly Dictionary<BaseModPackage, string> searchCache = new Dictionary<BaseModPackage, string>();
private readonly Dictionary<BaseModPackage, PreviewEntry> previews = new Dictionary<BaseModPackage, PreviewEntry>();
public ModManager manager => ELayer.core.mods;
private void Move(BaseModPackage p, ItemMod b, int a)
public bool HasFilter
{
get
{
if (searchTerms.Length == 0)
{
return filterMode != ModSearch.Filter.All;
}
return true;
}
}
private void Move(BaseModPackage p, int a)
{
List<object> items = list.items;
int num = items.IndexOf(p);
if (num < 0 || num + a < 0 || num + a >= items.Count)
{
SE.BeepSmall();
}
else
{
MoveTo(p, items[num + a] as BaseModPackage);
}
}
private void MoveTo(BaseModPackage p, BaseModPackage target)
{
List<BaseModPackage> packages = ELayer.core.mods.packages;
List<BaseModPackage> packages = manager.packages;
int num = packages.IndexOf(p);
if (num + a < 0 || num + a >= packages.Count || packages[num + a].builtin)
int num2 = ((target == null) ? (-1) : packages.IndexOf(target));
if (num < 0 || num2 < 0 || num == num2 || target.builtin)
{
SE.BeepSmall();
return;
}
packages.Move(p, a);
packages.Move(p, num2 - num);
SE.Tab();
textRestart.SetActive(enable: true);
ELayer.core.mods.SaveLoadOrder();
RefreshLists();
}
public void RefreshLists()
{
list.List();
list2.List();
if ((bool)textNoResult)
{
textNoResult.SetActive(HasFilter && list.items.Count == 0);
}
}
public override void OnInit() textRestart.SetActive(enable: true);
});
Instance = this;
foreach (BaseModPackage package in manager.packages)
{
package.UpdateMeta(updateOnly: true);
searchCache[package] = ModSearch.BuildText(package);
}
list.dragScrollView = GetComponentInChildren<UIScrollView>();
list.dragViewport = windows[0].Rect();
list.dragEdgeSize = 34f;
UIList uIList = list;
UIList uIList2 = list2;
UIList.Callback<ModPackage, ItemMod> obj = new UIList.Callback<ModPackage, ItemMod>
list.callbacks = CreateCallbacks(list, builtin: false);
list2.callbacks = CreateCallbacks(list2, builtin: true);
InitSearchUI();
CreatePresetUI();
panelHeader.SetText("info".lang());
RefreshLists();
ShowInfo(FirstInfoTarget());
list.dragEdgeSize = list.callbacks.GetMold()?.Rect().sizeDelta.y ?? 34f;
}
private UIList.Callback<ModPackage, ItemMod> CreateCallbacks(UIList target, bool builtin)
{
return new UIList.Callback<ModPackage, ItemMod>
{
onClick = delegate
{
},
onInstantiate = delegate(ModPackage a, ItemMod b)
{
a.UpdateMeta(updateOnly: true);
b.package = a;
string s = ELayer.core.mods.packages.IndexOf(a) + 1 + ". " + (a.isInPackages ? "[Local] " : "") + a.title;
b.buttonActivate.mainText.SetText(s, (!a.IsValidVersion()) ? FontColor.Bad : (a.activated ? FontColor.ButtonGeneral : FontColor.Passive));
string s = ELayer.core.mods.packages.IndexOf(a) + 1 + ". " + (a.isInPackages ? "[Local] " : "") + a.title.IsEmpty(a.dirInfo.Name);
b.buttonActivate.mainText.SetText(s, (!a.IsValidVersion() || a.blockedBy != null || !a.langDepError.IsEmpty()) ? FontColor.Bad : (a.activated ? FontColor.ButtonGeneral : FontColor.Passive));
b.buttonActivate.subText.text = a.version;
b.buttonLock.mainText.text = a.author;
b.buttonUp.SetActive(!a.builtin);b.buttonToggle.SetToggle(a.willActivate);
b.buttonUp.SetOnClick(delegate
{
Move(a, b, -1);
Move(a, -1);
});
b.buttonDown.SetOnClick(delegate
{
Move(a, b, 1);
Move(a, 1);
});
(b.buttonActivate.GetComponent<HoverRelay>() ?? b.buttonActivate.gameObject.AddComponent<HoverRelay>()).onEnter = delegate
{
ShowInfo(a);
};
UIButton bt = b.buttonToggle;
bt.SetOnClick(delegate
{{
Refresh();
UIContextMenu uIContextMenu = ELayer.ui.CreateContextMenuInteraction();
if (ELayer.debug.enable || (!BaseCore.IsOffline && a.isInPackages && !a.builtin && !ELayer.core.version.demo))
if (!a.builtin)
{
uIContextMenu.AddButton("mod_publish", delegate
if (ELayer.debug.enable || (!BaseCore.IsOffline && a.isInPackages && !ELayer.core.version.demo))
{
Core.TryWarnUpload(delegate
uIContextMenu.AddButton("mod_publish", delegate
{
Dialog.YesNo("mod_publish_warn".lang(a.title, a.id, a.author), delegate
Core.TryWarnUpload(delegate
{
ELayer.core.steam.CreateUserContent(a);
Dialog.YesNo("mod_publish_warn".lang(a.title, a.id, a.author), delegate
{
ELayer.core.steam.CreateUserContent(a);
});
});
});
});
}
if (!a.builtin)
{
}
uIContextMenu.AddButton(a.willActivate ? "mod_deactivate" : "mod_activate", delegate
{
SE.Click();
a.willActivate = !a.willActivate;
ELayer.core.mods.SaveLoadOrder();
list.List();
RefreshLists();
textRestart.SetActive(enable: true);
});
if (!a.isInPackages && !a.workshopId.IsEmpty()) string text = Path.Combine(BaseModManager.rootMod, path);
a.CopyContentTo(text);
ModPackage modPackage = manager.AddPackage(new DirectoryInfo(text), isInPackages: true);
modPackage.UpdateMeta(updateOnly: true);
searchCache[modPackage] = ModSearch.BuildText(modPackage);
manager.packages.Move(modPackage, manager.packages.IndexOf(a) - manager.packages.Count + 2);
modPackage.willActivate = false;
modPackage.activated = false;
ELayer.core.mods.SaveLoadOrder();
list.List();
RefreshLists();
textRestart.SetActive(enable: true);
});
} });
}
}
if (ModPreview.FindPreviewFile(a) != null || (bool)SteamPreview(a))
{
uIContextMenu.AddButton("mod_preview", delegate
{
ShowPreview(a);
});
}
if (!a.workshopId.IsEmpty())
{
uIContextMenu.AddButton("mod_info_workshop", delegate
{
SE.Click();
Application.OpenURL("https://steamcommunity.com/sharedfiles/filedetails/?id=" + a.workshopId.Trim());
});
}
uIContextMenu.AddButton("mod_info", delegate
{
SE.Click();
Util.ShowExplorer(a.dirInfo.FullName + "/package.xml");
if (!a.dirInfo.Exists)
{
SE.BeepSmall();
ELayer.ui.Say(a.dirInfo.FullName);
}
else
{
string text = a.dirInfo.FullName + "/package.xml";
Util.ShowExplorer(File.Exists(text) ? text : a.dirInfo.FullName);
}
});
uIContextMenu.Show();
});{
foreach (BaseModPackage package in manager.packages)
{
if (package.builtin)
{
list2.Add(package);
}
else
if (package.builtin == builtin && (builtin || Match(package)))
{
list.Add(package);
target.Add(package);
}
}
}, onDragReorder = delegate(ModPackage p, int a)
{
BaseCore.Instance.FreezeScreen(0.1f);
manager.packages.Move(p, a);
SE.Tab();
textRestart.SetActive(enable: true);
ELayer.core.mods.SaveLoadOrder();
list.List();
List<object> items = target.items;
int num = items.IndexOf(p);
MoveTo(p, items[Mathf.Clamp(num + a, 0, items.Count - 1)] as BaseModPackage);
},
canDragReorder = (ModPackage p) => !p.builtin
};
UIList.ICallback callbacks = obj;
uIList2.callbacks = obj;
uIList.callbacks = callbacks;
list.List();
list2.List();
}
private bool Match(BaseModPackage p)
{
if (!searchCache.TryGetValue(p, out var value))
{
value = (searchCache[p] = ModSearch.BuildText(p));
}
return ModSearch.Match(p, value, searchTerms, filterMode);
}
private void InitSearchUI()
{
if ((bool)inputSearch)
{
inputSearch.SetTextWithoutNotify("");
if (inputSearch.placeholder is Text text)
{
text.text = "mod_search".lang();
}
inputSearch.onValueChanged.AddListener(Search);
inputSearch.onSubmit.AddListener(Search);
}
if ((bool)buttonClearSearch)
{
buttonClearSearch.SetOnClick(ClearSearchText);
buttonClearSearch.SetActive(enable: false);
}
buttonFilter = windows[0].AddBottomButton("mod_filter", CycleFilter);
RefreshFilterButton();
if ((bool)textNoResult)
{
textNoResult.SetText("noResult".lang(), FontColor.Passive);
textNoResult.SetActive(enable: false);
}
}
public void Search(string s)
{
lastSearch = s ?? "";
timerSearch = 0.15f;
if ((bool)buttonClearSearch)
{
buttonClearSearch.SetActive(!lastSearch.IsEmpty());
}
}
private void ClearSearchText()
{
SE.Click();
if ((bool)inputSearch)
{
inputSearch.SetTextWithoutNotify("");
}
Search("");
}
public void ClearSearch()
{
if ((bool)inputSearch)
{
inputSearch.SetTextWithoutNotify("");
}
if ((bool)buttonClearSearch)
{
buttonClearSearch.SetActive(enable: false);
}
lastSearch = "";
timerSearch = 0f;
searchTerms = Array.Empty<string>();
filterMode = ModSearch.Filter.All;
RefreshFilterButton();
RefreshLists();
}
private void CycleFilter()
{
SE.Click();
filterMode = ModSearch.Filters[(int)(filterMode + 1) % ModSearch.Filters.Length];
RefreshFilterButton();
RefreshLists();
}
private void RefreshFilterButton()
{
if ((bool)buttonFilter)
{
buttonFilter.mainText.text = "mod_filter".lang() + ": " + FilterLabel(filterMode).lang();
windows[0].rectBottom.RebuildLayout(recursive: true);
}
}
private static string FilterLabel(ModSearch.Filter f)
{
return f switch
{
ModSearch.Filter.Enabled => "mod_filter_enabled",
ModSearch.Filter.Disabled => "mod_filter_disabled",
ModSearch.Filter.Problems => "mod_filter_problem",
ModSearch.Filter.Local => "mod_filter_local",
ModSearch.Filter.Workshop => "mod_filter_workshop",
_ => "all",
};
}
private void LateUpdate()
{
if (timerSearch > 0f)
{
timerSearch -= Core.delta;
if (timerSearch <= 0f)
{
timerSearch = 0f;
searchTerms = ModSearch.Terms(lastSearch);
RefreshLists();
}
}
if ((bool)inputSearch)
{
bool isFocused = inputSearch.isFocused;
EventSystem current = EventSystem.current;
if (wasSearchFocused && !isFocused && (bool)current && current.currentSelectedGameObject == inputSearch.gameObject)
{
current.SetSelectedGameObject(null);
}
wasSearchFocused = isFocused;
}
}
private PreviewEntry GetThumb(BaseModPackage p)
{
if (previews.TryGetValue(p, out var value))
{
return value;
}
value = new PreviewEntry();
bool owns;
Texture2D texture2D = LoadPreviewTexture(p, mipmap: true, out value.kind, out owns);
if ((bool)texture2D)
{
Texture2D texture2D2 = ModPreview.Downscale(texture2D, 280, owns);
value.sprite = texture2D2.ToSprite();
value.ownsTexture = owns || texture2D2 != texture2D;
}
previews[p] = value;
return value;
}
private static Texture2D LoadPreviewTexture(BaseModPackage p, bool mipmap, out ModPreview.PreviewType kind, out bool owns)
{
kind = ModPreview.PreviewType.None;
owns = true;
FileInfo fileInfo = ModPreview.FindPreviewFile(p);
if (fileInfo != null)
{
try
{
Texture2D texture2D = ModPreview.LoadTexture(File.ReadAllBytes(fileInfo.FullName), out kind, mipmap);
if ((bool)texture2D)
{
return texture2D;
}
}
catch (Exception ex)
{
Debug.LogWarning("#mod preview " + fileInfo.FullName + ": " + ex.Message);
}
}
Texture2D texture2D2 = SteamPreview(p);
if ((bool)texture2D2)
{
owns = false;
if (kind == ModPreview.PreviewType.None)
{
kind = ModPreview.PreviewType.Jpeg;
}
}
return texture2D2;
}
private static Texture2D SteamPreview(BaseModPackage p)
{
if (!(p.item is WorkshopItem workshopItem) || !workshopItem.previewImage || workshopItem.previewImage.width <= 2)
{
return null;
}
return workshopItem.previewImage;
}
private BaseModPackage FirstInfoTarget()
{
using (List<object>.Enumerator enumerator = list.items.GetEnumerator())
{
if (enumerator.MoveNext())
{
return enumerator.Current as BaseModPackage;
}
}
if (manager.packages.Count <= 0)
{
return null;
}
return manager.packages[0];
}
private void ShowInfo(BaseModPackage p)
{
if (!panelNote || p == null || p == panelTarget)
{
return;
}
panelTarget = p;
UINote n = panelNote;
n.Clear();
n.AddHeader(p.title.IsEmpty(p.dirInfo.Name));
PreviewEntry thumb = GetThumb(p);
if ((bool)thumb.sprite)
{
AddPreviewBox(n, thumb.sprite, delegate
{
ShowPreview(p);
});
if (thumb.kind == ModPreview.PreviewType.Gif)
{
n.AddText("mod_preview_gif".lang(), FontColor.Passive);
}
}
else
{
n.AddText(((thumb.kind == ModPreview.PreviewType.None) ? "mod_preview_none" : "mod_preview_unsupported").lang(), FontColor.Passive);
}
if (!p.author.IsEmpty())
{
AddTopic("author", p.author);
}
if (!p.version.IsEmpty())
{
AddTopic("version", p.version);
}
if (!p.id.IsEmpty())
{
FitValue(AddTopic("mod_info_id", p.id));
}
string text = ModLoadOrderPreset.WorkshopId(p);
FitValue(AddTopic(text.IsEmpty() ? "mod_filter_local" : "mod_filter_workshop", text.IsEmpty() ? p.dirInfo.Name : text));
if (!p.builtin && !p.willActivate)
{
AddTopic("status", "mod_filter_disabled".lang());
}
if (p.blockedBy != null)
{
n.AddText("mod_info_blocked".lang(p.blockedBy.title.IsEmpty(p.blockedBy.id)), FontColor.Bad);
}
if (!p.langDepError.IsEmpty())
{
n.AddText(p.langDepError, FontColor.Bad);
}
if (p.duplicateOf != null)
{
n.AddText("mod_info_duplicate".lang(p.duplicateOf.dirInfo?.Name ?? p.duplicateOf.id), FontColor.Bad);
}
if (!p.IsValidVersion())
{
n.AddText("mod_info_old_version".lang(p.version, ELayer.core.versionMod.GetText()), FontColor.Bad);
}
if (!p.parseError.IsEmpty())
{
n.AddText(p.parseError, FontColor.Bad);
}
string[] tags = p.tags;
if (tags != null && tags.Length > 0)
{
AddTopic("mod_info_tags", string.Join(", ", p.tags));
}
AddIdList(n, "mod_info_requires", p.dependency);
AddIdList(n, "incompatible", p.incompatible);
AddIdList(n, "mod_info_load_after", p.loadAfter);
AddIdList(n, "mod_info_load_before", p.loadBefore);
if (!p.description.IsEmpty())
{
n.Space(8);
n.AddText(p.description);
}
n.Build();
panelScroll.content.anchoredPosition = Vector2.zero;
UIItem AddTopic(string lang, string value)
{
UIItem uIItem = n.AddTopic(lang, value);
uIItem.text1.alignment = TextAnchor.LowerLeft;
return uIItem;
}
}
private static void AddPreviewBox(UINote n, Sprite sprite, Action onClick)
{
n.AddImage(sprite);
RectTransform rectTransform = n.transform.GetChild(n.transform.childCount - 1).Rect();
rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, 240f);
Image componentInChildren = rectTransform.GetComponentInChildren<Image>();
RectTransform rectTransform2 = componentInChildren.rectTransform;
rectTransform2.anchorMin = Vector2.zero;
rectTransform2.anchorMax = Vector2.one;
rectTransform2.pivot = new Vector2(0.5f, 0.5f);
rectTransform2.anchoredPosition = Vector2.zero;
rectTransform2.sizeDelta = Vector2.zero;
componentInChildren.preserveAspect = true;
Button button = componentInChildren.gameObject.AddComponent<Button>();
button.transition = Selectable.Transition.None;
button.onClick.AddListener(delegate
{
onClick();
});
}
private static void FitValue(UIItem item)
{
if ((bool)item && (bool)item.text2)
{
item.text2.resizeTextForBestFit = true;
item.text2.horizontalOverflow = HorizontalWrapMode.Wrap;
item.text2.resizeTextMinSize = 9;
item.text2.resizeTextMaxSize = item.text2.fontSize;
}
}
private static void AddIdList(UINote n, string lang, string[][] rows)
{
if (rows != null && rows.Length != 0)
{
List<string> list = (from row in rows
where row != null && row.Length > 0 && !row[0].IsEmpty()
select row[0]).ToList();
if (list.Count > 0)
{
n.AddTopic(lang, string.Join(", ", list)).text1.alignment = TextAnchor.LowerLeft;
}
}
}
private void ShowPreview(BaseModPackage a)
{
SE.Click();
ModPreview.PreviewType kind;
bool owns;
Texture2D tex = LoadPreviewTexture(a, mipmap: false, out kind, out owns);
if (!tex)
{
SE.BeepSmall();
ELayer.ui.Say("mod_preview_unsupported");
return;
}
Sprite image = tex.ToSprite();
LayerImage layerImage = ELayer.ui.AddLayer<LayerImage>();
layerImage.SetImage(image);
layerImage.SetOnKill(delegate
{
UnityEngine.Object.Destroy(tex);
if (owns)
{
UnityEngine.Object.Destroy(tex);
}
});
}
private void CreatePresetUI()
{
windows[0].AddBottomButton("mod_preset", ShowPresetMenu);
}
private void ShowPresetMenu()
{
SE.Click();
if (ModManager.disableMod)
{
Dialog.Ok("mod_preset_disabled");
return;
}
UIContextMenu uIContextMenu = ELayer.ui.CreateContextMenu();
uIContextMenu.AddButton("mod_preset_save", SavePreset);
uIContextMenu.AddButton("mod_preset_load", delegate
{
SelectPreset(ApplyPresetFile);
});
uIContextMenu.AddButton("mod_preset_delete", delegate
{
SelectPreset(DeletePreset);
});
uIContextMenu.AddButton("mod_preset_copy", CopyPreset);
uIContextMenu.AddButton("mod_preset_paste", PastePreset);
uIContextMenu.AddButton("mod_preset_folder", delegate
{
Directory.CreateDirectory(CorePath.PathLoadOrderPreset);
Util.ShowExplorer(CorePath.PathLoadOrderPreset, selectFirstFile: true);
});
uIContextMenu.Show();
}
private void SavePreset()
{
Dialog.InputName("mod_preset_name", "mod_preset_default_name".lang(), delegate(bool cancel, string text)
{
if (!cancel)
{
string name = (text ?? "").Trim().SanitizeFileName().Trim();
if (name.IsEmpty())
{
SE.BeepSmall();
}
else if (File.Exists(ModManager.GetPresetPath(name)))
{
Dialog.YesNo("mod_preset_overwrite".lang(name), delegate
{
WritePreset(name);
});
}
else
{
WritePreset(name);
}
}
});
}
private void WritePreset(string name)
{
if (!manager.SavePreset(name, out var _))
{
SE.BeepSmall();
return;
}
SE.Click();
ELayer.ui.Say("mod_preset_saved".lang(name));
}
private void SelectPreset(Action<FileInfo> onSelect)
{
List<FileInfo> files = manager.ListPresets();
if (files.Count == 0)
{
Dialog.Ok("mod_preset_none");
return;
}
Dialog.List("mod_preset_select", files, (FileInfo f) => Path.GetFileNameWithoutExtension(f.Name), delegate(int i, string _)
{
onSelect(files[i]);
return true;
}, canCancel: true);
}
private void ApplyPresetFile(FileInfo file)
{
if (!manager.TryLoadPresetFile(file, out var preset, out var _))
{
Dialog.Ok("mod_preset_invalid");
}
else
{
ConfirmPreset(preset);
}
}
private void DeletePreset(FileInfo file)
{
string name = Path.GetFileNameWithoutExtension(file.Name);
Dialog.YesNo("mod_preset_delete_confirm".lang(name), delegate
{
if (file.Exists)
{
file.Delete();
}
SE.Trash();
ELayer.ui.Say("mod_preset_deleted".lang(name));
});
}
private void CopyPreset()
{
ModLoadOrderPreset.Preset preset = ModLoadOrderPreset.Save(manager.packages, "", ELayer.core.version.GetText());
if (preset.entries.Count == 0)
{
SE.BeepSmall();
return;
}
GUIUtility.systemCopyBuffer = ModLoadOrderPreset.Serialize(preset);
SE.Click();
ELayer.ui.Say("mod_preset_copied");
}
private void PastePreset()
{
if (!ModLoadOrderPreset.TryParse(GUIUtility.systemCopyBuffer, out var preset, out var _))
{
Dialog.Ok("mod_preset_invalid");
return;
}
if (preset.name.IsEmpty())
{
preset.name = "mod_preset_default_name".lang();
}
ConfirmPreset(preset);
}
private void ConfirmPreset(ModLoadOrderPreset.Preset preset)
{
List<ModLoadOrderPreset.Entry> list = ModLoadOrderPreset.FindMissing(manager.packages, preset);
if (list.Count == 0)
{
ApplyPreset(preset);
return;
}
Dialog.YesNo("mod_preset_missing".lang(DescribeEntries(list, 15)), delegate
{
ApplyPreset(preset);
}, null, "mod_preset_apply", "cancel");
}
private static string DescribeEntries(List<ModLoadOrderPreset.Entry> entries, int max)
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < entries.Count && i < max; i++)
{
ModLoadOrderPreset.Entry entry = entries[i];
stringBuilder.Append(entry.title.IsEmpty() ? entry.id : (entry.title + " (" + entry.id + ")")).Append('\n');
}
if (entries.Count > max)
{
stringBuilder.Append("mod_preset_more".lang((entries.Count - max).ToString() ?? "")).Append('\n');
}
return stringBuilder.ToString().TrimEnd();
}
private void ApplyPreset(ModLoadOrderPreset.Preset preset)
{
if (HasFilter)
{
ClearSearch();
}
ModLoadOrderPreset.ApplyResult applyResult = manager.ApplyPreset(preset);
SE.Tab();
textRestart.SetActive(enable: true);
RefreshLists();
string text = ELayer.core.version.GetText();
if (!preset.gameVersion.IsEmpty() && preset.gameVersion != text)
{
ELayer.ui.Say("mod_preset_version_warn".lang(preset.gameVersion, text));
}
ELayer.ui.Say("mod_preset_applied".lang(preset.name, applyResult.enabled.ToString() ?? "", applyResult.missing.Count.ToString() ?? ""));
}
public void Refresh() public override void OnKill()
{
if ((bool)TooltipManager.Instance)
{
TooltipManager.Instance.HideTooltips(immediate: true);
}
foreach (PreviewEntry value in previews.Values)
{
if ((bool)value.sprite)
{
if (value.ownsTexture)
{
UnityEngine.Object.Destroy(value.sprite.texture);
}
UnityEngine.Object.Destroy(value.sprite);
}
}
previews.Clear();
ELayer.core.mods.SaveLoadOrder();
if (Instance == this)
{
Instance = null;
}
}
}ModManager โ
using IniParser.Model;
using Steamworks;
using UnityEngine;
using UnityEngine.UI;
[Serializable]
public class ModManager : ModManagerCore
{
private sealed class WorkshopDownload
{
public readonly WorkshopItem item;
public readonly BaseModPackage package;
public readonly bool isUpdate;
public float lastChange;
public float progress;
public string Title => package.title.IsEmpty(item.Title).IsEmpty(item.FileId.ToString());
public WorkshopDownload(BaseModPackage package, float now)
{
this.package = package;
item = (WorkshopItem)package.item;
isUpdate = package.installed;
lastChange = now;
}
}
public static List<object> ListPluginObject = new List<object>();
public static bool disableMod;public class ModManager : ModManagerCore
public List<FileInfo> replaceFiles = new List<FileInfo>();
private HashSet<ulong> _subscribedItems;
private readonly HashSet<ulong> _blockedItems = new HashSet<ulong>();
private int _missingContent;
public static List<string> ListChainLoad => BaseModManager.listChainLoad;
public static DirectoryInfo DirWorkshop => Instance.dirWorkshop;
public new static ModManager Instance => (ModManager)BaseModManager.Instance;
public static bool IsInitialized => BaseModManager.isInitialized;
public new static ModManager Instance => (ModManager)BaseModManager.Instance;
public override void Init(string path, string defaultPackage = "_Elona")
{
base.Init(path, defaultPackage);public override void Init(string path, string defaultPackage = "_Elona")
Debug.Log("Core Mod:" + BaseModManager.rootDefaultPacakge);
}
public static string FormatLoadOrder(BaseModPackage p)
{
string arg = p.dirInfo?.FullName;
int num = (p.willActivate ? 1 : 0);
if (ModLoadOrderPreset.IsValidId(p.id))
{
return $"{arg},{num},{p.id.Trim()}";
}
return "";
}
public void SaveLoadOrder()
{
if (!disableMod)
if (disableMod)
{
List<string> contents = (from p in packages
where !p.builtin && p.dirInfo.Exists
select $"{p.dirInfo.FullName},{(p.willActivate ? 1 : 0)}").ToList();
File.WriteAllLines(CorePath.rootExe + "loadorder.txt", contents);
return;
}
List<string> list = new List<string>();
foreach (BaseModPackage package in packages)
{
string str = package.dirInfo?.FullName;
if (!package.builtin && !str.IsEmpty())
{
list.Add(FormatLoadOrder(package));
}
}
File.WriteAllLines(CorePath.PathLoadOrder, list);
}
public void LoadLoadOrder()
{
string path = CorePath.rootExe + "loadorder.txt";
if (!File.Exists(path))
foreach (BaseModPackage package in packages)
{
package.orderIndex = -1;
}
string pathLoadOrder = CorePath.PathLoadOrder;
if (!File.Exists(pathLoadOrder))
{
return;
}
Dictionary<string, BaseModPackage> dictionary = new Dictionary<string, BaseModPackage>();
foreach (BaseModPackage package in packages)
Dictionary<string, BaseModPackage> dictionary = new Dictionary<string, BaseModPackage>(StringComparer.OrdinalIgnoreCase);
Dictionary<string, BaseModPackage> dictionary2 = new Dictionary<string, BaseModPackage>();
foreach (BaseModPackage package2 in packages)
{
if (!package.builtin)
if (!package2.builtin)
{
dictionary[package.dirInfo.FullName] = package;
string text = NormalizeOrderPath(package2.dirInfo?.FullName);
if (!text.IsEmpty())
{
dictionary.TryAdd(text, package2);
}
string text2 = BaseModPackage.NormalizeId(package2.id);
if (!text2.IsEmpty())
{
dictionary2.TryAdd(text2, package2);
}
}
}
int num = 0;
string[] array = File.ReadAllLines(path);
HashSet<BaseModPackage> hashSet = new HashSet<BaseModPackage>();
string[] array = File.ReadAllLines(pathLoadOrder);
for (int i = 0; i < array.Length; i++)
{
string[] array2 = array[i].Split(',');
if (dictionary.TryGetValue(array2[0], out var value))
if (ParseLoadOrderLine(array[i], out var path, out var activate, out var id))
{
value.loadPriority = num;
value.willActivate = array2[1] == "1";
if (!dictionary.TryGetValue(NormalizeOrderPath(path), out var value))
{
dictionary2.TryGetValue(BaseModPackage.NormalizeId(id) ?? "", out value);
}
if (value != null && hashSet.Add(value))
{
value.orderIndex = num;
value.willActivate = activate;
num++;
}
}
num++;
}
static bool ParseLoadOrderLine(string line, out string reference, out bool reference2, out string reference3)
{
reference = null;
reference2 = true;
reference3 = null;
if (line.IsEmpty() || line.Trim().IsEmpty())
{
return false;
}
int num2 = line.LastIndexOf(',');
if (num2 <= 0)
{
return false;
}
string text3 = line[(num2 + 1)..].Trim();
if (text3 == "0" || text3 == "1")
{
reference = line[..num2];
reference2 = text3 == "1";
return !reference.IsEmpty();
}
int num3 = line.LastIndexOf(',', num2 - 1);
if (num3 <= 0)
{
return false;
}
string text4 = line[(num3 + 1)..num2].Trim();
if (text4 != "0" && text4 != "1")
{
return false;
}
reference = line[..num3];
reference2 = text4 == "1";
reference3 = text3;
return !reference.IsEmpty();
}
}
private static string NormalizeOrderPath(string path)
{
if (!path.IsEmpty())
{
return path.NormalizePath().TrimEnd('/');
}
return "";
}
public static string GetPresetPath(string name)
{
return CorePath.PathLoadOrderPreset + name.SanitizeFileName() + ".txt";
}
public List<FileInfo> ListPresets()
{
if (!Directory.Exists(CorePath.PathLoadOrderPreset))
{
return new List<FileInfo>();
}
return new DirectoryInfo(CorePath.PathLoadOrderPreset).GetFiles("*.txt", SearchOption.TopDirectoryOnly).OrderBy((FileInfo f) => f.Name, StringComparer.OrdinalIgnoreCase).ToList();
}
public bool SavePreset(string name, out string path)
{
path = GetPresetPath(name);
ModLoadOrderPreset.Preset preset = ModLoadOrderPreset.Save(packages, name, EClass.core.version.GetText());
if (disableMod || preset.entries.Count == 0)
{
return false;
}
Directory.CreateDirectory(CorePath.PathLoadOrderPreset);
File.WriteAllText(path, ModLoadOrderPreset.Serialize(preset));
return true;
}
public bool TryLoadPresetFile(FileInfo file, out ModLoadOrderPreset.Preset preset, out string error)
{
preset = null;
string text;
try
{
text = File.ReadAllText(file.FullName);
}
catch (Exception ex)
{
error = ex.Message;
return false;
}
if (!ModLoadOrderPreset.TryParse(text, out preset, out error))
{
return false;
}
if (preset.name.IsEmpty())
{
preset.name = Path.GetFileNameWithoutExtension(file.Name);
}
return true;
}
public ModLoadOrderPreset.ApplyResult ApplyPreset(ModLoadOrderPreset.Preset preset, bool disableOthers = true)
{
ModLoadOrderPreset.ApplyResult result = ModLoadOrderPreset.Apply(packages, preset, disableOthers);
SaveLoadOrder();
return result;
}
public IEnumerator RefreshMods(Action onComplete, bool syncMods)
{
bool flag = !BaseCore.IsOffline && syncMods && UserGeneratedContent.Client.GetNumSubscribedItems() != 0;
if ((bool)_loading)
{
UnityEngine.Object.Destroy(_loading.gameObject);
}
_loading = Util.Instantiate<LoadingScreen>("LoadingScreen");
bool flag = !BaseCore.IsOffline && syncMods && UserGeneratedContent.Client.GetNumSubscribedItems() != 0;
WaitForEndOfFrame awaiter = new WaitForEndOfFrame();
packages.Clear();
_subscribedItems = null;
_blockedItems.Clear();
_missingContent = 0;
disableMod |= Application.isEditor && EClass.debug.skipMod;
LoadLocalPackages();
LoadCustomPackage();public IEnumerator RefreshMods(Action onComplete, bool syncMods)
{
yield return LoadWorkshopPackages();
}
else
{
DirectoryInfo[] directories = dirWorkshop.GetDirectories();
foreach (DirectoryInfo dir in directories)
{
AddPackage(dir);
}
}
LoadCachedWorkshopPackages();
}
InitPackagesMeta();
LoadLoadOrder();
packages.Sort((BaseModPackage a, BaseModPackage b) => a.loadPriority - b.loadPriority);
foreach (BaseModPackage item in packages.Where((BaseModPackage p) => !p.isInPackages && p.willActivate && !p.id.IsEmpty()))
SortPackages();
List<BaseModPackage> list = packages.Where((BaseModPackage p) => p.CanActivate && !p.parseError.IsEmpty()).ToList();
if (list.Count > 0)
{
if (mappedPackages.TryGetValue(item.id, out var value) && value.isInPackages)
{
value.hasPublishedPackage = true;
}
Halt(list);
yield break;
}
_loading.Log($"Total number of mods:{packages.Count}");
_loading.Log("Activating Mods...");
yield return awaiter;
ActivatePackages();
foreach (BaseModPackage package in packages)
{
if (package.activated)
{
mappedPackages[package.id] = package as ModPackage;
}
}
MapActivatedPackages();
BaseModManager.isInitialized = true;
yield return awaiter;
onComplete?.Invoke();public IEnumerator RefreshMods(Action onComplete, bool syncMods)
yield return null;
}
private void Halt(List<BaseModPackage> broken)
{
List<string> list = broken.Select((BaseModPackage p) => p.title.IsEmpty(p.dirInfo?.Name) + ": package.xml does not parse - " + p.parseError).ToList();
list.Add("Fix the package.xml, or unsubscribe / delete the mod, then restart the game.");
string text = string.Join("\n", list);
Debug.LogError("#mod game will not start:\n" + text);
EGui.CreatePopup(() => new EGui.UpdateInfo(text), (EGui _) => false);
}
private void SortPackages()
{
LoadLoadOrder();
List<BaseModPackage> list = ModOrder.SolveOrder(packages, useLoadorder: true);
if (list.Count != packages.Count)
{
Debug.LogError($"#mod order {list.Count} of {packages.Count} packages");
return;
}
packages.Clear();
packages.AddRange(list);
}
private void MapActivatedPackages()
{
foreach (BaseModPackage item in packages.Where((BaseModPackage p) => p.activated && !p.id.IsEmpty()))
{
mappedPackages[item.id] = item as ModPackage;
}
}
public ModPackage AddPackage(DirectoryInfo dir, bool isInPackages = false)
{
ModPackage modPackage = new ModPackagepublic ModPackage AddPackage(DirectoryInfo dir, bool isInPackages = false)
dirInfo = new DirectoryInfo(dir.FullName.NormalizePath()),
installed = true,
isInPackages = isInPackages,
loadPriority = priorityIndex,
Mapping = new FileMapping(dir)
};
packages.Add(modPackage);
priorityIndex++;
return modPackage;
}
public ModPackage AddWorkshopPackage(WorkshopItem item, bool isInPackages = false)
{
bool itemInstallInfo = UserGeneratedContent.Client.GetItemInstallInfo(item.FileId, out var _, out var folderPath, out var _);
if (folderPath == null)
if (folderPath.IsEmpty())
{
folderPath = Path.Combine(DirWorkshop.FullName, item.FileId.ToString());
}public void LoadLocalPackages()
DirectoryInfo[] array = directories;
foreach (DirectoryInfo directoryInfo in array)
{
if (!disableMod || !(directoryInfo.Name != "_Elona") || !(directoryInfo.Name != "_Lang_Chinese"))
if (!disableMod || BaseModPackage.IsBuiltinDir(directoryInfo.Name))
{
if (directoryInfo.Name == "Mod_FixedPackageLoader")
{public void LoadCustomPackage()
}
}
public IEnumerator LoadWorkshopPackages()
public void InitPackagesMeta()
{
WaitForEndOfFrame awaiter = new WaitForEndOfFrame();
UgcQuery activeQuery = UgcQuery.GetSubscribed(withLongDescription: false, withMetadata: false, withKeyValueTags: false, withAdditionalPreviews: false, 0u);
activeQuery.Execute(HandleWorkshopQuery);
_loading.Log("Fetching subscriptions...(Hit ESC to cancel)");
while (activeQuery.handle != UGCQueryHandle_t.Invalid && !UnityEngine.Input.GetKey(KeyCode.Escape))
Text status = _loading.Log("Initializing mods...");
HashSet<BaseModPackage> hashSet = new HashSet<BaseModPackage>();
int num = 0;
foreach (BaseModPackage package in packages)
{
yield return awaiter;
num++;
try
{
if (!package.Init())
{
hashSet.Add(package);
Debug.LogWarning("Not a package: " + package.dirInfo.FullName);
continue;
}
if (package.parseError.IsEmpty() && package.id.IsEmpty())
{
hashSet.Add(package);
Debug.LogWarning("No <id> in package.xml, skipped: " + package.dirInfo.FullName);
continue;
}
if (!package.id.IsEmpty())
{
mappedPackages[package.id] = package as ModPackage;
}
Debug.Log(package.ToString());
SetStatus(status, $"Initializing mods {num}/{packages.Count}: {package.title}");
}
catch (Exception ex)
{
_loading.Log("Mod " + package.title + "/" + package.id + " has failed to initialize, " + ex.Message);
Debug.LogError(ex);
}
}
if (hashSet.Count > 0)
{
packages.RemoveAll(hashSet.Contains);
_loading.Log($"Ignored {hashSet.Count} folder(s) without a usable package.xml");
}
SetStatus(status, $"Initialized {packages.Count} mods");
}
public void ActivatePackages()
{
BaseModManager.listChainLoad.Clear();
ListPluginObject.Clear();
ActivatePackageList();
ModUtil.OnModsActivated();
ModUtil.LoadTypeFallback();
}
public void ActivatePackageList()
{
Dictionary<string, BaseModPackage> loaded = new Dictionary<string, BaseModPackage>();
Dictionary<string, BaseModPackage> claimed = new Dictionary<string, BaseModPackage>();
int num = 0;
foreach (BaseModPackage package in packages)
{
package.blockedBy = null;
package.langDepError = null;
}
yield return UpdateWorkshopPackages();
void HandleWorkshopQuery(UgcQuery query)
Dictionary<string, BaseModPackage> dictionary = new Dictionary<string, BaseModPackage>();
foreach (BaseModPackage package2 in packages)
{
foreach (WorkshopItem results in query.ResultsList)
string text = BaseModPackage.NormalizeId(package2.id);
if (text != null && !package2.hasPublishedPackage)
{
AddWorkshopPackage(results);
dictionary.TryAdd(text, package2);
}
}
foreach (ModPackage item in from p in packages.OfType<ModPackage>()
where !disableMod || p.builtin
select p)
{
if (!item.IsValidVersion())
{
_loading?.Log("Skipped (made for game " + item.version + "): " + item.title + "/" + item.id);
}
else
{
if (item.banned)
{
continue;
}
if (item.CanActivate)
{
BaseModPackage baseModPackage = FindIncompatible(item, loaded, claimed);
if (baseModPackage != null)
{
item.blockedBy = baseModPackage;
num++;
_loading?.Log("Blocked: " + item.title + "/" + item.id + " <-> " + baseModPackage.title + "/" + baseModPackage.id);
continue;
}
string text2 = UnmetDependency(item, loaded, dictionary);
if (text2 != null)
{
item.langDepError = text2;
_loading?.Log("Skipped (" + text2 + "): " + item.title + "/" + item.id);
continue;
}
}
try
{
item.Activate();
}
catch (Exception ex)
{
_loading?.Log("Failed to activate mod " + item.title + ": " + ex.Message);
}
finally
{
if (item.activated)
{
BaseModManager.listChainLoad.Add(item.dirInfo.FullName);
RegisterLoaded(item, loaded, claimed);
}
}
}
}
if (num > 0)
{
Debug.LogWarning($"#mod {num} package(s) skipped due to incompatibility");
}
}
private IEnumerator UpdateWorkshopPackages()
private string UnmetDependency(BaseModPackage p, Dictionary<string, BaseModPackage> loaded, Dictionary<string, BaseModPackage> installed)
{
_loading?.Log("Updating subscriptions...");
WaitForEndOfFrame awaiter = new WaitForEndOfFrame();
while (true)
if (p.dependency == null)
{
return null;
}
string[][] dependency = p.dependency;
foreach (string[] array in dependency)
{
if (array == null || array.Length == 0)
{
continue;
}
BaseModPackage baseModPackage = null;
BaseModPackage baseModPackage2 = null;
bool flag = false;
foreach (BaseModPackage item in packages.Where((BaseModPackage p) => !p.installed))
string[] array2 = array;
for (int j = 0; j < array2.Length; j++)
{
if (!(item.item is WorkshopItem { IsBanned: false } workshopItem))
string text = BaseModPackage.NormalizeId(array2[j]);
if (text == null)
{
continue;
}
flag = true;
string text = "Downloading " + workshopItem.Title + ": ";
BaseModPackage baseModPackage = item;
if ((object)baseModPackage.progressText == null)
if (loaded.ContainsKey(text))
{
baseModPackage.progressText = _loading?.Log(text);
flag = true;
break;
}
if (item.downloadStarted && workshopItem.DownloadCompletion >= 1f)
if (!installed.TryGetValue(text, out var value) || value == p)
{
item.installed = true;
if ((bool)item.progressText)
{
item.progressText.text = text + "Done!";
}
continue;
}
else if (workshopItem.IsDownloading || workshopItem.IsDownloadPending)
if (packages.IndexOf(value) > packages.IndexOf(p))
{
int num = Mathf.FloorToInt(workshopItem.DownloadCompletion * 100f);
if ((bool)item.progressText)
if (baseModPackage == null)
{
item.progressText.text = text + num + "%";
baseModPackage = value;
}
}
else if (!item.downloadStarted)
else if (baseModPackage2 == null)
{
item.downloadStarted = true;
workshopItem.DownloadItem(highPriority: true);
Debug.Log("Start downloading: " + workshopItem.Title + " | " + $"Installed={workshopItem.IsInstalled}, " + $"Downloading={workshopItem.IsDownloading}, " + $"Pending={workshopItem.IsDownloadPending}");
baseModPackage2 = value;
}
}
if (!flag)
{
yield break;
if (baseModPackage != null)
{
return "requires " + baseModPackage.title.IsEmpty(baseModPackage.dirInfo?.Name) + ", which loads after this mod - move it above";
}
if (baseModPackage2 != null)
{
return "requires " + baseModPackage2.title.IsEmpty(baseModPackage2.dirInfo?.Name) + ", which is installed but did not load";
}
return "requires " + string.Join(" or ", array) + ", which is not installed";
}
if (UnityEngine.Input.GetKey(KeyCode.Escape))
}
return null;
}
private static BaseModPackage FindIncompatible(BaseModPackage p, Dictionary<string, BaseModPackage> loaded, Dictionary<string, BaseModPackage> claimed)
{
if (p.builtin)
{
return null;
}
string text = BaseModPackage.NormalizeId(p.id);
if (text == null)
{
return null;
}
string[][] incompatible = p.incompatible;
if (incompatible != null)
{
string[][] array = incompatible;
foreach (string[] array2 in array)
{
break;
if (array2 == null)
{
continue;
}
string[] array3 = array2;
for (int j = 0; j < array3.Length; j++)
{
string text2 = BaseModPackage.NormalizeId(array3[j]);
if (text2 == null)
{
continue;
}
BaseModPackage value;
if (text2 == text)
{
Debug.Log("#mod incompatible: '" + p.id + "' self decl, ignored");
}
else if (loaded.TryGetValue(text2, out value) && value != null)
{
if (!value.builtin)
{
return value;
}
Debug.Log("#mod incompatible: '" + p.id + "' targets builtin '" + value.id + "', ignored");
}
}
}
yield return awaiter;
}
Debug.Log("Workshop updating cancelled");
if (claimed.TryGetValue(text, out var value2) && value2 != null && !value2.builtin)
{
return value2;
}
return null;
}
public void InitPackagesMeta()
private static void RegisterLoaded(BaseModPackage p, Dictionary<string, BaseModPackage> loaded, Dictionary<string, BaseModPackage> claimed)
{
foreach (BaseModPackage package in packages)
if (p.builtin)
{
try
return;
}
string text = BaseModPackage.NormalizeId(p.id);
if (text == null)
{
return;
}
loaded[text] = p;
string[][] incompatible = p.incompatible;
if (incompatible == null)
{
return;
}
string[][] array = incompatible;
foreach (string[] array2 in array)
{
if (array2 == null)
{
continue;
}
string[] array3 = array2;
for (int j = 0; j < array3.Length; j++)
{
if (package.Init())
string text2 = BaseModPackage.NormalizeId(array3[j]);
if (text2 != null && !(text2 == text))
{
mappedPackages[package.id] = package as ModPackage;
claimed.TryAdd(text2, p);
}
_loading?.Log(package.ToString());
}
catch (Exception ex)
}
}
public IEnumerator LoadWorkshopPackages()
{
PublishedFileId_t[] subscribedItems = UserGeneratedContent.Client.GetSubscribedItems();
if (!subscribedItems.IsEmpty())
{
_subscribedItems = subscribedItems.Select((PublishedFileId_t id) => id.m_PublishedFileId).ToHashSet();
yield return QuerySubscriptions(subscribedItems);
yield return DownloadSubscriptions();
if (_missingContent > 0)
{
package.willActivate = false;
_loading?.Log("Mod " + package.title + "/" + package.id + " has failed to initialize, reason: " + ex.Message);
yield return new WaitForSecondsRealtime(3f);
}
}
}
public void ActivatePackages()
private IEnumerator QuerySubscriptions(PublishedFileId_t[] subscribed)
{
BaseModManager.listChainLoad.Clear();
ListPluginObject.Clear();
foreach (ModPackage package in packages)
WaitForEndOfFrame awaiter = new WaitForEndOfFrame();
Text status = _loading.Log("Fetching subscriptions...");
Dictionary<ulong, WorkshopItem> fetched = new Dictionary<ulong, WorkshopItem>();
bool aborted = false;
for (int i = 0; i < subscribed.Length; i += 50)
{
if ((disableMod && !package.builtin) || !package.IsValidVersion())
PublishedFileId_t[] array = subscribed.Skip(i).Take(50).ToArray();
UgcQuery query = UgcQuery.Get(array);
bool completed = false;
bool discard = false;
SetStatus(status, $"Fetching subscriptions {i + array.Length}/{subscribed.Length}...(Hit ESC to cancel)");
if (query == null || !query.Execute(OnQueryCompleted))
{
continue;
Debug.LogWarning("Workshop: steam rejected the subscription query");
query?.Dispose();
aborted = true;
break;
}
try
float deadline = Time.realtimeSinceStartup + 30f;
while (!completed)
{
package.Activate();
if (package.activated)
if (IsCancelRequested() || Time.realtimeSinceStartup > deadline)
{
BaseModManager.listChainLoad.Add(package.dirInfo.FullName);
discard = true;
aborted = true;
query.Dispose();
break;
}
yield return awaiter;
}
catch (Exception ex)
if (aborted)
{
Debug.LogWarning("Workshop: subscription query cancelled or timed out");
break;
}
void OnQueryCompleted(UgcQuery result)
{
_loading.Log("Failed to activate mod: " + package.title + ", reason: " + ex.Message);
completed = true;
if (discard)
{
return;
}
foreach (WorkshopItem results in result.ResultsList)
{
SteamUGCDetails_t sourceItemDetails = results.SourceItemDetails;
if (sourceItemDetails.m_eResult == EResult.k_EResultOK && sourceItemDetails.m_nPublishedFileId.m_PublishedFileId != 0L)
{
fetched[sourceItemDetails.m_nPublishedFileId.m_PublishedFileId] = results;
}
}
}
}
ModUtil.OnModsActivated();
ModUtil.LoadTypeFallback();
foreach (WorkshopItem value in fetched.Values)
{
if (value.IsBanned)
{
_blockedItems.Add(value.FileId.m_PublishedFileId);
_missingContent++;
}
else
{
AddWorkshopPackage(value);
}
}
SetStatus(status, $"Fetched {fetched.Count}/{subscribed.Length} subscriptions");
if (aborted)
{
yield break;
}
for (int j = 0; j < subscribed.Length; j++)
{
PublishedFileId_t publishedFileId_t = subscribed[j];
if (!fetched.ContainsKey(publishedFileId_t.m_PublishedFileId) && !Directory.Exists(Path.Combine(dirWorkshop.FullName, publishedFileId_t.ToString())))
{
_missingContent++;
}
}
}
private IEnumerator DownloadSubscriptions()
{
float now = Time.realtimeSinceStartup;
List<WorkshopDownload> queue = (from p in packages
where p.item is WorkshopItem workshopItem && (!p.installed || workshopItem.IsNeedsUpdate)
select new WorkshopDownload(p, now)).ToList();
if (queue.Count == 0)
{
yield break;
}
WaitForEndOfFrame awaiter = new WaitForEndOfFrame();
Text status = _loading.Log($"Downloading {queue.Count} mods...");
Dictionary<ulong, EResult> results = new Dictionary<ulong, EResult>();
int total = queue.Count;
int completed = 0;
float lastActivity = now;
float nextStatus = 0f;
UserGeneratedContent.Client.EventItemDownloaded.AddListener(OnItemDownloaded);
try
{
while (queue.Count > 0)
{
now = Time.realtimeSinceStartup;
for (int num = queue.Count - 1; num >= 0; num--)
{
WorkshopDownload workshopDownload = queue[num];
WorkshopItem item = workshopDownload.item;
ulong publishedFileId = item.FileId.m_PublishedFileId;
string path = null;
string reason = null;
bool flag = false;
EResult value;
if (!workshopDownload.package.downloadStarted)
{
workshopDownload.package.downloadStarted = true;
workshopDownload.lastChange = now;
if (item.DownloadItem(highPriority: true))
{
Debug.Log("Start downloading: " + workshopDownload.Title + " | " + $"Installed={item.IsInstalled}, " + $"Update={item.IsNeedsUpdate}, " + $"Downloading={item.IsDownloading}, " + $"Pending={item.IsDownloadPending}");
continue;
}
reason = "cannot start the download";
}
else if (results.TryGetValue(publishedFileId, out value) && value != EResult.k_EResultOK)
{
reason = $"download failed ({value})";
}
else if (IsItemReady(item, out path))
{
flag = true;
}
else
{
if (item.IsDownloadPending)
{
workshopDownload.lastChange = now;
continue;
}
if (item.IsDownloading)
{
float downloadCompletion = item.DownloadCompletion;
if (downloadCompletion > workshopDownload.progress)
{
workshopDownload.progress = downloadCompletion;
float lastChange;
lastActivity = (lastChange = now);
workshopDownload.lastChange = lastChange;
}
continue;
}
if (!(now - workshopDownload.lastChange > 20f))
{
continue;
}
reason = "cannot start the download";
}
queue.RemoveAt(num);
lastActivity = now;
if (flag)
{
completed++;
InstallWorkshopPackage(workshopDownload, path);
}
else
{
FailWorkshopPackage(workshopDownload, reason);
}
}
if (queue.Count == 0)
{
break;
}
if (IsCancelRequested())
{
AbortDownloads(queue, "cancelled");
break;
}
if (now - lastActivity > 90f)
{
AbortDownloads(queue, "not responding");
break;
}
if (now >= nextStatus)
{
nextStatus = now + 0.5f;
WorkshopDownload workshopDownload2 = queue.Find((WorkshopDownload d) => d.item.IsDownloading) ?? queue[0];
SetStatus(status, $"Downloading mods {completed}/{total}: " + $"{workshopDownload2.Title} {Mathf.FloorToInt(workshopDownload2.progress * 100f)}%...(Hit ESC to cancel)");
}
yield return awaiter;
}
}
finally
{
UserGeneratedContent.Client.EventItemDownloaded.RemoveListener(OnItemDownloaded);
}
SetStatus(status, $"Downloaded {completed}/{total} mods");
packages.RemoveAll((BaseModPackage p) => p.item is WorkshopItem && !p.installed);
void OnItemDownloaded(DownloadItemResult_t result)
{
results[result.m_nPublishedFileId.m_PublishedFileId] = result.m_eResult;
}
}
public void LoadCachedWorkshopPackages()
{
HashSet<string> hashSet = packages.Select((BaseModPackage p) => p.dirInfo.FullName).ToHashSet(StringComparer.OrdinalIgnoreCase);
DirectoryInfo[] directories = dirWorkshop.GetDirectories();
foreach (DirectoryInfo directoryInfo in directories)
{
ulong result;
bool flag = ulong.TryParse(directoryInfo.Name, out result);
if ((!flag || !_blockedItems.Contains(result)) && (_subscribedItems == null || (flag && _subscribedItems.Contains(result))) && !hashSet.Contains(new DirectoryInfo(directoryInfo.FullName.NormalizePath()).FullName))
{
ModPackage modPackage = AddPackage(directoryInfo);
if (flag)
{
modPackage.workshopId = directoryInfo.Name;
}
}
}
}
private void InstallWorkshopPackage(WorkshopDownload download, string path)
{
BaseModPackage package = download.package;
package.installed = true;
package.dirInfo = new DirectoryInfo(path.NormalizePath());
if (package is ModPackage modPackage)
{
modPackage.Mapping = new FileMapping(package.dirInfo);
}
Debug.Log("Downloaded: " + download.Title + " -> " + package.dirInfo.FullName);
}
private void FailWorkshopPackage(WorkshopDownload download, string reason)
{
if (download.isUpdate)
{
Debug.LogWarning("Workshop update failed: " + download.Title + ", " + reason);
return;
}
_missingContent++;
Debug.LogWarning("Workshop download failed: " + download.Title + ", " + reason);
}
private void AbortDownloads(List<WorkshopDownload> queue, string reason)
{
foreach (WorkshopDownload item in queue)
{
FailWorkshopPackage(item, reason);
}
queue.Clear();
}
private static bool IsItemReady(WorkshopItem item, out string path)
{
path = null;
if (!item.IsInstalled || item.IsNeedsUpdate || item.IsDownloading || item.IsDownloadPending)
{
return false;
}
if (UserGeneratedContent.Client.GetItemInstallInfo(item.FileId, out var _, out path, out var _) && !path.IsEmpty())
{
return Directory.Exists(path);
}
return false;
}
private static bool IsCancelRequested()
{
return UnityEngine.Input.GetKey(KeyCode.Escape);
}
private static void SetStatus(Text status, string message)
{
if ((bool)status)
{
status.text = message;
}
}
public override void ParseExtra(DirectoryInfo dir, BaseModPackage package)ModUtil โ
private static void LoadEffectTemplate()
}
}
public static DynamicInvoker Call(object instance, params string[] names)
{
return new DynamicInvoker(instance?.GetType(), instance, names);
}
public static DynamicInvoker Call(Type type, params string[] names)
{
return new DynamicInvoker(type, null, names);
}
public static DynamicInvoker Call<T>(params string[] names)
{
return new DynamicInvoker(typeof(T), null, names);
}
public static DynamicInvoker CallType(string typeName, params string[] names)
{
return new DynamicInvoker(DynamicReflection.FindType(typeName), null, names);
}
public static DynamicInvoker Construct(Type type)
{
return DynamicInvoker.Constructor(type);
}
public static DynamicInvoker Construct<T>()
{
return DynamicInvoker.Constructor(typeof(T));
}
public static DynamicInvoker ConstructType(string typeName)
{
return DynamicInvoker.Constructor(DynamicReflection.FindType(typeName));
}
public static DynamicAccessor Access(object instance, params string[] names)
{
return new DynamicAccessor(instance?.GetType(), instance, names);
}
public static DynamicAccessor Access(Type type, params string[] names)
{
return new DynamicAccessor(type, null, names);
}
public static DynamicAccessor Access<T>(params string[] names)
{
return new DynamicAccessor(typeof(T), null, names);
}
public static DynamicAccessor AccessType(string typeName, params string[] names)
{
return new DynamicAccessor(DynamicReflection.FindType(typeName), null, names);
}
public static DynamicTarget Target(Type type, params string[] names)
{
return new DynamicTarget(type, names);
}
public static DynamicTarget Target<T>(params string[] names)
{
return new DynamicTarget(typeof(T), names);
}
public static DynamicTarget TargetType(string typeName, params string[] names)
{
return new DynamicTarget(DynamicReflection.FindType(typeName), names);
}
public static MethodInfo FindMethod(Type type, params string[] names)
{
return new DynamicTarget(type, names).Get();
}
public static MethodInfo FindMethod<T>(params string[] names)
{
return new DynamicTarget(typeof(T), names).Get();
}
public static MethodInfo FindGetter(Type type, params string[] names)
{
return DynamicTarget.Accessor(type, names, setter: false);
}
public static MethodInfo FindGetter<T>(params string[] names)
{
return DynamicTarget.Accessor(typeof(T), names, setter: false);
}
public static MethodInfo FindSetter(Type type, params string[] names)
{
return DynamicTarget.Accessor(type, names, setter: true);
}
public static MethodInfo FindSetter<T>(params string[] names)
{
return DynamicTarget.Accessor(typeof(T), names, setter: true);
}
public static ConstructorInfo FindConstructor(Type type, params Type[] paramTypes)
{
return DynamicTarget.Constructor(type, paramTypes);
}
public static ConstructorInfo FindConstructor<T>(params Type[] paramTypes)
{
return DynamicTarget.Constructor(typeof(T), paramTypes);
}
public static Type FindType(string typeName)
{
return DynamicReflection.FindType(typeName);
}
public static T Coerce<T>(object value)
{
return DynamicReflection.Coerce<T>(value);
}
public static SerializableSoundData GetSoundMeta(string soundPath)
{
string path = Path.ChangeExtension(soundPath, ".json");Player โ
public class PartySetup : EClass
[JsonProperty]
public int fishArtifact;
[JsonProperty]
public int staminaRecovery;
[JsonProperty]
public float angle;public void OnAdvanceRealHour()
}
}
public void RecoverStamina(int a)
{
if (a >= staminaRecovery)
{
a = staminaRecovery;
}
if (a != 0)
{
staminaRecovery -= a;
EClass.pc.stamina.Mod(a);
}
}
public void RefreshDomain()
{
domains.Clear();Recipe โ
{
text = "(" + source.row.GetField<string>("id") + ")";
}
return text.ToTitleCase();
text = text.ToTitleCase();
if (source.row is CardRow && (source.row as CardRow).quality == 4)
{
text = "โ
" + text;
}
return text;
}
public virtual string GetDetail()TCText โ
private static bool ExtractSoundTag(ref string text, out string id, out float chโฆ)
{
id = null;
chance = 1f;
int num = text.IndexOf("<sound", StringComparison.Ordinal);
int num = text.IndexOf("<sound=", StringComparison.Ordinal);
if (num == -1)
{
return false;private static bool ExtractSoundTag(ref string text, out string id, out float chโฆ)
{
return false;
}
int num3 = num + 6;
int num3 = num + 7;
string text2 = text.Substring(num3, num2 - num3);
int num4 = text2.IndexOf(',');
if (num4 == -1)WidgetHP โ
gaugeStamina.textNow.SetSize(gaugeStamina.textNow.orgSize + extra.fontSize);
gaugeHP.UpdateValue(EMono.pc.hp, EMono.pc.MaxHP);
gaugeMP.UpdateValue(EMono.pc.mana.value, EMono.pc.mana.max);
gaugeStamina.UpdateValue(EMono.pc.stamina.value, EMono.pc.stamina.max);
gaugeStamina.UpdateValue(EMono.pc.stamina.value, EMono.pc.stamina.max, EMono.player.staminaRecovery);
Color c = EMono.Colors.Dark.gradientHP.Evaluate((float)EMono.pc.hp / (float)EMono.pc.MaxHP);
gaugeHP.textNow.text = "".TagColor(c, EMono.pc.hp.ToString() ?? "") + (extra.showMax ? (" / " + EMono.pc.MaxHP) : "");
c = EMono.Colors.Dark.gradientMP.Evaluate((float)EMono.pc.mana.value / (float)EMono.pc.mana.max);