Skip to content

ElectricalProgressive QoL: EOven × XSkills AmbiguousMatchException #41

Description

@Baldrvolsk

English (short)

While an electric oven (eoven) is cooking with XSkills integration enabled, the server spam-logs AmbiguousMatchException thousands of times per minute. EP resolves XSkills.Cooking.ApplyAbilities via Type.GetMethod(name) without binding argument types; XSkills has overloaded ApplyAbilities methods, so reflection fails every tick.

English — full issue body (copy to GitHub)

Title: EOven XSkills integration: AmbiguousMatchException on Cooking.ApplyAbilities (massive server log spam)

Labels (suggested): bug, qol, xskills, performance

Summary

With XSkills present, ElectricalProgressive QoL enables cooking-ability integration (ElectricalProgressiveQoL: интеграция с XSkills включена). BlockEntityEOven.ApplyCookingAbilities reflects into XSkills.Cooking.ApplyAbilities using an ambiguous Type.GetMethod call. That throws System.Reflection.AmbiguousMatchException on every apply attempt while the oven is active, producing tens of thousands of [Warning] lines in a short window and likely skipping XSkills cooking bonuses for EOven output.

Environment

Component Version / note
Vintage Story 1.22.3 (Stable), network 1.22.6, API 1.22.0
electricalprogressivecore 3.3.0
electricalprogressivebasics 3.3.1
electricalprogressiveqol 3.3.1
xlib xlibfork-1.0.35 (xlib)
xskills xskillsfork-1.0.93 (xskills)
OS / runtime Linux server (Ubuntu), .NET (Server GC)

Steps to reproduce

  1. Install ElectricalProgressive (Core + Basics + QoL) and XSkills/XLib on a 1.22.3 server.
  2. Confirm startup log: XSkills integration enabled for QoL.
  3. Place/power an electricalprogressiveqol:eoven-* and cook food (vanilla meals and/or alchemy cuttings observed).
  4. Watch server-main.log while the oven ticks.

Expected

  • XSkills cooking abilities apply to EOven results, or
  • Integration is skipped quietly if the API cannot be bound.
  • No per-tick exception spam.

Actual

Continuous warnings, peak rate on our server ≈ 2000 log lines/minute, total 34156 warnings in ≈40 minutes (11:40–12:21 local server time, 2026-08-08). Spam stopped after cooking activity on that oven ended (oven was also broken/picked up mid-window).

Stack trace (representative)

[Warning] Error applying cooking abilities: System.Reflection.AmbiguousMatchException:
Ambiguous match found for 'XSkills.Cooking Void ApplyAbilities(
  Vintagestory.API.Common.ItemSlot,
  Vintagestory.API.Common.IPlayer,
  Single, Single,
  Vintagestory.API.Common.ItemStack[],
  Single)'.
   at System.RuntimeType.GetMethodImplCommon(...)
   at System.Type.GetMethod(String name, BindingFlags bindingAttr)
   at ElectricalProgressive.Content.Block.EOven.BlockEntityEOven.ApplyCookingAbilities(
        ItemStack prevStack, Int32 slotIndex)
     in .../ElectricalProgressive-QOL/Content/Block/EOven/BlockEntityEOven.cs:line 635

Root cause (mod-side)

BlockEntityEOven.cs ≈ line 635 uses reflection roughly equivalent to:

typeof(XSkills.Cooking).GetMethod("ApplyAbilities", bindingFlags);

XSkills exposes multiple ApplyAbilities overloads. GetMethod(string) without a parameter-type array is undefined when overloads exist → AmbiguousMatchException.

The exception is caught and logged as a warning, so the server stays up, but:

  1. Log I/O and exception overhead scale with oven tick rate × slots.
  2. Cooking abilities almost certainly never apply for EOven in this configuration.

Suggested fix

In ApplyCookingAbilities (QoL):

  1. Prefer a compile-time / soft reference or documented public API if XSkills exposes one.
  2. If reflection must stay, bind explicitly, e.g.:
var method = cookingType.GetMethod(
    "ApplyAbilities",
    BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, // as appropriate
    binder: null,
    types: new[] {
        typeof(ItemSlot),
        typeof(IPlayer),
        typeof(float),
        typeof(float),
        typeof(ItemStack[]),
        typeof(float)
    },
    modifiers: null);
  1. Cache the MethodInfo (or a compiled delegate) once at startup; on failure, disable integration and log once.
  2. Optionally rate-limit warnings if binding fails at runtime.

Impact

  • Severity: Medium (no crash; high log spam / wasted CPU; broken XSkills bonus path for EOven).
  • Multiplayer servers with electric ovens + XSkills are especially affected.

Notes

  • Observed oven location example (world): 511284, 144, 512578 (eoven-enabled-east), contents included alchemy cooked cuttings.
  • Not correlated with evening lag reports on the same day; this is a daytime cooking-session spam event.

Русский (кратко)

Электропечь EP (QoL) при включённой интеграции с XSkills спамит серверный лог: AmbiguousMatchException на reflection-вызове XSkills.Cooking.ApplyAbilities (метод перегружен, а GetMethod без типов аргументов). За ≈40 минут — ≈34k warning’ов. Сервер не падает, но бонусы готовки XSkills для EOven, скорее всего, не применяются.

Русский — подробности

Заголовок: EOven + XSkills: AmbiguousMatchException на ApplyAbilities (массовый спам лога)

Суть

При старте: ElectricalProgressiveQoL: интеграция с XSkills включена.
BlockEntityEOven.ApplyCookingAbilities (файл BlockEntityEOven.cs, ≈строка 635) ищет метод через Type.GetMethod("ApplyAbilities") без сигнатуры. В XSkills несколько перегрузок → ambiguous match на каждый тик печи.

Окружение

  • VS 1.22.3, EP QoL 3.3.1, Core 3.3.0, Basics 3.3.1
  • XSkills xskillsfork-1.0.93, XLib xlibfork-1.0.35

Наблюдение (наш сервер, 2026-08-08)

  • Окно: 11:40–12:21
  • Всего warning’ов: 34156
  • Пик: порядка 2000 строк/мин
  • После окончания готовки / поломки печи спам прекратился

Ожидаемое поведение

Либо корректный вызов нужной перегрузки и применение способностей, либо одноразовый отказ интеграции без спама.

Предлагаемый фикс

Явно указать типы параметров в GetMethod, закэшировать MethodInfo, при неудаче отключить интеграцию и залогировать один раз.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions