using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GK2.Framework;
using HarmonyLib;
using LazyBearTechnology;
using UnityEngine;
using UnityEngine.UI;
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace GK2MoveBuilding
{
internal static class Cm
{
public static ConfigDescription D(string description, string name, int order, bool advanced = false, AcceptableValueBase range = null, bool browsable = true)
{
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Expected O, but got Unknown
ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes();
configurationManagerAttributes.DispName = name;
configurationManagerAttributes.Order = order;
ConfigurationManagerAttributes configurationManagerAttributes2 = configurationManagerAttributes;
if (advanced)
{
configurationManagerAttributes2.IsAdvanced = true;
}
if (!browsable)
{
configurationManagerAttributes2.Browsable = false;
}
return new ConfigDescription(description, range, new object[1] { configurationManagerAttributes2 });
}
}
}
internal sealed class ConfigurationManagerAttributes
{
public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput);
public bool? ShowRangeAsPercent;
public Action<ConfigEntryBase> CustomDrawer;
public CustomHotkeyDrawerFunc CustomHotkeyDrawer;
public bool? Browsable;
public string Category;
public object DefaultValue;
public bool? HideDefaultButton;
public bool? HideSettingName;
public string Description;
public string DispName;
public int? Order;
public bool? ReadOnly;
public bool? IsAdvanced;
public Func<object, string> ObjToStr;
public Func<string, object> StrToObj;
}
namespace GK2MoveBuilding
{
internal static class Framework
{
private sealed class Entry : Gk2ModBase
{
private readonly Gk2ModMetadata _meta = new Gk2ModMetadata("gk2.movebuilding", "GK2 Move Buildings", "SaintArchI", "0.4.15", FwText.L("Adds a Move button to the build menu, so a building can be picked up and put down elsewhere."), false, false);
private readonly IReadOnlyList<Gk2ModDependency> _deps = (IReadOnlyList<Gk2ModDependency>)(object)new Gk2ModDependency[1]
{
new Gk2ModDependency("ru.superman4eg.gk2.framework", "0.1.0", "0.2.0", false)
};
public override Gk2ModMetadata Metadata => _meta;
public override IReadOnlyList<Gk2ModDependency> Dependencies => _deps;
public override void OnRegister(Gk2ModContext context)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
Gk2Settings settings = context.Settings;
settings.AddKeybind("Hotkeys", "MoveModifier", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), FwText.L("Move modifier"), FwText.L("Hold this in the game's remove mode and click a building to move it instead of demolishing it."), 0);
settings.AddToggle("General", "CarryContents", false, FwText.L("Carry the contents"), FwText.L("Chests, racks and shelves keep what they hold when moved, instead of dropping it on the ground."), 2);
}
}
public const string FrameworkGuid = "ru.superman4eg.gk2.framework";
public static void TryRegister(BaseUnityPlugin plugin)
{
try
{
if (AppDomain.CurrentDomain.GetAssemblies().Any((Assembly a) => a.GetName().Name == "GK2.Framework"))
{
Register(plugin);
}
}
catch (Exception ex)
{
Plugin.Log.LogInfo((object)("Mod Framework not used: " + ex.Message));
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Register(BaseUnityPlugin plugin)
{
FrameworkApi.RegisterMod((IGk2Mod)(object)new Entry(), plugin.Config);
Plugin.Log.LogInfo((object)"Registered in GK2 Mod Framework");
}
}
internal static class FwText
{
private static readonly string[] Langs = new string[10] { "ru", "de", "fr", "es", "pt", "pl", "tr", "ja", "zh", "ko" };
private static int _idx = -2;
private static readonly Dictionary<string, string[]> Table = new Dictionary<string, string[]>
{
{
"Carry the contents",
new string[10] { "Переносить содержимое", "Inhalt mitnehmen", "Transporter le contenu", "Llevar el contenido", "Levar o conteúdo", "Przenoś zawartość", "İçeriği taşı", "中身ごと運ぶ", "连同内容一起搬", "내용물 함께 옮기기" }
},
{
"Chests, racks and shelves keep what they hold when moved, instead of dropping it on the ground.",
new string[10] { "Сундуки, стойки и полки при переносе сохраняют содержимое, а не вываливают его на землю.", "Truhen, Gestelle und Regale behalten beim Versetzen ihren Inhalt, statt ihn auf den Boden fallen zu lassen.", "Les coffres, râteliers et étagères gardent leur contenu une fois déplacés, au lieu de le laisser tomber au sol.", "Los cofres, soportes y estantes conservan su contenido al moverlos, en vez de soltarlo en el suelo.", "Baús, suportes e prateleiras mantêm o conteúdo ao serem movidos, em vez de derrubá-lo no chão.", "Skrzynie, stojaki i półki po przeniesieniu zachowują zawartość, zamiast wysypać ją na ziemię.", "Sandıklar, raflar ve askılar taşındığında içindekileri yere dökmek yerine korur.", "チェスト・ラック・棚を移動しても、中身を地面に落とさずそのまま保ちます。", "移动箱子、架子和货架时保留里面的东西,而不是掉在地上。", "상자, 거치대, 선반을 옮겨도 내용물을 바닥에 쏟지 않고 그대로 유지합니다." }
},
{
"Put the zombie down",
new string[10] { "Ставить зомби на землю", "Zombie absetzen", "Poser le zombie", "Dejar al zombi en el suelo", "Pôr o zumbi no chão", "Postaw zombie na ziemi", "Zombiyi yere bırak", "ゾンビを降ろす", "放下僵尸", "좀비 내려놓기" }
},
{
"A zombie working in a moved building is put down where the building stood.",
new string[10] { "Зомби, работавший в перенесённой постройке, остаётся стоять там, где она была.", "Ein Zombie, der im versetzten Gebäude arbeitete, wird dort abgesetzt, wo das Gebäude stand.", "Un zombie qui travaillait dans le bâtiment déplacé est posé là où se trouvait le bâtiment.", "Un zombi que trabajaba en el edificio movido se queda donde estaba el edificio.", "Um zumbi que trabalhava na construção movida fica onde ela estava.", "Zombie pracujący w przeniesionym budynku zostaje postawiony tam, gdzie budynek stał.", "Taşınan binada çalışan zombi, binanın durduğu yere bırakılır.", "移動した建物で働いていたゾンビは、建物のあった場所に降ろされます。", "在被移动建筑里工作的僵尸会被放在建筑原来的位置。", "옮긴 건물에서 일하던 좀비는 건물이 있던 자리에 내려놓습니다." }
},
{
"Move modifier",
new string[10] { "Клавиша переноса", "Versetzen-Taste", "Touche de déplacement", "Tecla para mover", "Tecla para mover", "Klawisz przenoszenia", "Taşıma tuşu", "移動キー", "移动键", "이동 키" }
},
{
"Hold this in the game's remove mode and click a building to move it instead of demolishing it.",
new string[10] { "Зажмите её в режиме сноса и щёлкните постройку, чтобы перенести её, а не снести.", "Halte sie im Abrissmodus gedrückt und klicke auf ein Gebäude, um es zu versetzen statt abzureißen.", "Maintenez-la en mode démolition et cliquez sur un bâtiment pour le déplacer au lieu de le démolir.", "Mantenla pulsada en el modo de demolición y haz clic en un edificio para moverlo en vez de derribarlo.", "Segure-a no modo de demolição e clique numa construção para movê-la em vez de demoli-la.", "Przytrzymaj go w trybie rozbiórki i kliknij budynek, by go przenieść zamiast rozebrać.", "Yıkım modunda bunu basılı tutup bir binaya tıklarsan bina yıkılmak yerine taşınır.", "撤去モードでこのキーを押しながら建物をクリックすると、壊さずに移動できます。", "在拆除模式下按住此键并点击建筑,即可移动而不是拆除。", "철거 모드에서 이 키를 누른 채 건물을 클릭하면 철거하지 않고 옮깁니다." }
},
{
"Adds a Move button to the build menu, so a building can be picked up and put down elsewhere.",
new string[10] { "Добавляет в меню строительства кнопку «Перенести»: постройку можно поднять и поставить в другом месте.", "Fügt dem Baumenü eine Versetzen-Schaltfläche hinzu, damit ein Gebäude aufgenommen und woanders abgestellt werden kann.", "Ajoute un bouton Déplacer au menu de construction, pour prendre un bâtiment et le poser ailleurs.", "Añade un botón Mover al menú de construcción para recoger un edificio y ponerlo en otro sitio.", "Adiciona um botão Mover ao menu de construção, para pegar uma construção e colocá-la em outro lugar.", "Dodaje do menu budowy przycisk Przenieś, by podnieść budynek i postawić go gdzie indziej.", "İnşa menüsüne bir Taşı düğmesi ekler; bir bina kaldırılıp başka bir yere konabilir.", "建築メニューに「移動」ボタンを追加し、建物を持ち上げて別の場所に置けるようにします。", "在建造菜单中加入“移动”按钮,可以把建筑拿起并放到别处。", "건설 메뉴에 이동 버튼을 추가해 건물을 들어 다른 곳에 놓을 수 있게 합니다." }
}
};
private static int Index
{
get
{
if (_idx != -2)
{
return _idx;
}
string text = null;
try
{
text = FrameworkLanguage();
}
catch
{
}
text = (text ?? "en").ToLowerInvariant();
_idx = -1;
for (int i = 0; i < Langs.Length; i++)
{
if (text.StartsWith(Langs[i]))
{
_idx = i;
break;
}
}
return _idx;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static string FrameworkLanguage()
{
return FrameworkLocalization.CurrentLanguage;
}
public static string L(string en)
{
int index = Index;
if (index < 0 || en == null || !Table.TryGetValue(en, out var value) || index >= value.Length || string.IsNullOrEmpty(value[index]))
{
return en;
}
return value[index];
}
}
internal enum MoveState
{
Idle,
Pending,
Placing
}
internal static class Move
{
internal static MoveState State = MoveState.Idle;
internal static bool Armed;
internal static Wgo Source;
private static BuildingDef _def;
private static string _replaceTo;
private static WgoData _placed;
private static WgoData _relink;
private static WgoData _removed;
private static float _sweepUntil = -1f;
private static Vector3 _sweepAt;
private static bool _abortPending;
private static float _finishedAt = -100f;
private static object _rescuedSave;
private static bool _rescueDisabled;
private static float _saveSeenAt = -1f;
private const float NeighbourRange = 6f;
private static bool _wasBuilding;
private static readonly FieldInfo _cachedController = AccessTools.Field(typeof(BuildController), "cachedInstance");
internal static BuildData MoveBuildData { get; private set; }
public static bool Active => State != MoveState.Idle;
public static bool JustFinished => Time.unscaledTime - _finishedAt < 3f;
public static BuildData NewEntry()
{
MoveBuildData = BuildData.GetDataForRemove();
return MoveBuildData;
}
public static bool IsMoveEntry(BuildData data)
{
return data != null && object.ReferenceEquals(data, MoveBuildData);
}
public static bool TryPickUp(Wgo target)
{
if ((Object)(object)target == (Object)null || Active)
{
return false;
}
if (IsConveyorElement(target))
{
Plugin.Log.LogWarning((object)("Move: " + target.Id + " is a conveyor element - those cannot be moved yet"));
return false;
}
BuildingDef value = null;
string replaceTo = null;
try
{
GameBalance.Me.buildableWgos.TryGetValue(target.Id, out value);
}
catch
{
}
if (value == null)
{
try
{
GameBalance.Me.buildableWgos.TryGetValue(target.Id + "_place", out value);
}
catch
{
}
if (value != null)
{
replaceTo = target.Id;
}
}
if (value == null)
{
Plugin.Log.LogWarning((object)("Move: no buildable definition for " + target.Id + ", leaving the remove action alone"));
return false;
}
Source = target;
_def = value;
_replaceTo = replaceTo;
_placed = null;
State = MoveState.Pending;
Plugin.Log.LogInfo((object)("Move: picked up " + target.Id + " (" + ((BalanceBaseObject)value).id + ")"));
return true;
}
public static void StartPlacing()
{
State = MoveState.Idle;
try
{
BuildManager instance = LazySingleton<BuildManager>.Instance;
if ((Object)(object)instance == (Object)null || (Object)(object)Source == (Object)null)
{
Cancel("no build manager");
return;
}
ResetCursor();
DisablePointer();
Traverse val = Traverse.Create((object)instance);
Wgo value = val.Field("currentBuildDesk").GetValue<Wgo>();
List<Inventory> value2 = val.Field("additionalInventories").GetValue<List<Inventory>>();
BuildData dataForBuild = BuildData.GetDataForBuild(_def);
State = MoveState.Placing;
instance.EnableBuildMode(value, dataForBuild, new List<NeedItemData>(), value2);
Plugin.Log.LogInfo((object)("Move: placing " + ((BalanceBaseObject)_def).id + " - the cost is waived"));
}
catch (Exception ex)
{
Cancel("could not start placing: " + ex.Message);
}
}
private static bool IsConveyorElement(Wgo target)
{
try
{
if (target.Data is ConveyorWgoData)
{
return true;
}
return GameBalance.Me.conveyorWgosCache?.ContainsKey(target.Id) ?? false;
}
catch
{
return false;
}
}
public static bool RefuseSpecialPointer(WgoBuildPointer pointer)
{
if (State != MoveState.Placing || (Object)(object)pointer == (Object)null)
{
return false;
}
if (((object)pointer).GetType() == typeof(WgoBuildPointer))
{
return false;
}
Plugin.Log.LogWarning((object)("Move: " + ((_def == null) ? "?" : ((BalanceBaseObject)_def).id) + " is placed by " + ((object)pointer).GetType().Name + ", which a move cannot finish - the move is called off, nothing was changed"));
State = MoveState.Idle;
Armed = false;
Source = null;
_def = null;
_placed = null;
_replaceTo = null;
_abortPending = true;
return true;
}
public static void TickAbort()
{
if (_abortPending)
{
_abortPending = false;
EndBuildMode();
ResetCursor();
DisablePointer();
ClearExtensionIcons();
Ui.SayCannotMove();
}
}
public static void MakeFree(WgoBuildPointer pointer)
{
if (State != MoveState.Placing || (Object)(object)pointer == (Object)null)
{
return;
}
try
{
Traverse val = Traverse.Create((object)pointer);
val.Field("canTakeResources").SetValue((object)(Func<bool>)(() => true));
val.Field("takeResourcesAction").SetValue((object)(Action)delegate
{
});
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not waive the cost: " + ex.Message));
}
}
public static void FilterOwnColliders(Collider[] hits, ref int count)
{
if (State != MoveState.Placing || (Object)(object)Source == (Object)null || hits == null || count <= 0)
{
return;
}
int num = Math.Min(count, hits.Length);
int num2 = 0;
for (int i = 0; i < num; i++)
{
Collider val = hits[i];
Wgo val2 = null;
if ((Object)(object)val != (Object)null)
{
try
{
val2 = ((Component)val).GetComponentInParent<Wgo>();
}
catch
{
}
}
if (!((Object)(object)val2 != (Object)null) || !((Object)(object)val2 == (Object)(object)Source))
{
hits[num2++] = val;
}
}
for (int j = num2; j < num; j++)
{
hits[j] = null;
}
count = num2;
}
public static void OnWgoAdded(WgoData data)
{
if (State == MoveState.Placing && data != null && _placed != data)
{
if (!IsTheMovedKind(data))
{
Plugin.Log.LogInfo((object)("Move: ignored " + ((ObjectLinkedToDefinition<WGODef>)(object)data).id + " appearing during the move"));
return;
}
_placed = data;
Plugin.Log.LogInfo((object)("Move: the new building is " + ((ObjectLinkedToDefinition<WGODef>)(object)data).id));
}
}
private static bool IsTheMovedKind(WgoData data)
{
try
{
if ((Object)(object)Source == (Object)null || string.IsNullOrEmpty(((ObjectLinkedToDefinition<WGODef>)(object)data).id))
{
return false;
}
if (Source.Data == data)
{
return false;
}
string id = ((ObjectLinkedToDefinition<WGODef>)(object)data).id;
if (id == Source.Id)
{
return true;
}
if (!string.IsNullOrEmpty(_replaceTo) && id == _replaceTo + "_place")
{
return true;
}
if (_def != null && !string.IsNullOrEmpty(((BalanceBaseObject)_def).id))
{
string text = ((!((BalanceBaseObject)_def).id.EndsWith("_p")) ? ((BalanceBaseObject)_def).id : ((BalanceBaseObject)_def).id.Substring(0, ((BalanceBaseObject)_def).id.Length - 2));
if (id == text)
{
return true;
}
}
}
catch
{
}
return false;
}
public static void TickRescue()
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Invalid comparison between Unknown and I4
try
{
if (_rescueDisabled)
{
return;
}
MainGame instance = MainGame.Instance;
GameSave val = ((!((Object)(object)instance != (Object)null) || (int)instance.gameState != 1) ? null : instance.GameSave);
if (val == null || val.worldData == null)
{
_saveSeenAt = -1f;
}
else
{
if (object.ReferenceEquals(val, _rescuedSave))
{
return;
}
if (_saveSeenAt < 0f)
{
_saveSeenAt = Time.unscaledTime;
}
else
{
if (Time.unscaledTime - _saveSeenAt < 5f)
{
return;
}
_rescuedSave = val;
_saveSeenAt = -1f;
int num = 0;
foreach (GameSceneData gameSceneData in val.worldData.gameSceneDataList)
{
if (gameSceneData == null || gameSceneData.wgoDataList == null)
{
continue;
}
WgoData[] array = gameSceneData.wgoDataList.ToArray();
foreach (WgoData val2 in array)
{
if (val2 == null || ((ObjectLinkedToDefinition<WGODef>)(object)val2).id == null || !((ObjectLinkedToDefinition<WGODef>)(object)val2).id.StartsWith("garden_"))
{
continue;
}
Inventory val3 = null;
try
{
val3 = val2.Inventory;
}
catch
{
}
if (val3 == null || val3.Data == null || val3.Data.Inventory == null)
{
continue;
}
List<Item> inventory = val3.Data.Inventory;
List<Item> list = inventory.Where((Item val4) => val4 != null && ((ObjectLinkedToDefinition<ItemDef>)(object)val4).id != null && ((ObjectLinkedToDefinition<ItemDef>)(object)val4).id.StartsWith("body")).ToList();
if (list.Count == 0)
{
continue;
}
foreach (Item item in list)
{
inventory.Remove(item);
}
try
{
val3.NotifyItemsRemoved(list);
}
catch
{
}
try
{
val2.MakeDrop(list);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Move: could not drop a body out of " + ((ObjectLinkedToDefinition<WGODef>)(object)val2).id + ": " + ex));
}
num += list.Count;
Plugin.Log.LogWarning((object)("Move: found " + Describe(list) + " inside " + ((ObjectLinkedToDefinition<WGODef>)(object)val2).id + " (left there by 0.4.9) - dropped beside it"));
}
}
if (num > 0)
{
Plugin.Log.LogWarning((object)("Move: rescued " + num + " body/bodies from garden beds"));
}
}
}
}
catch (Exception ex2)
{
_rescueDisabled = true;
Plugin.Log.LogWarning((object)("Move: body rescue skipped: " + ex2.Message));
}
}
public static void Finish()
{
if (State != MoveState.Placing)
{
return;
}
State = MoveState.Idle;
Armed = false;
_finishedAt = Time.unscaledTime;
EndBuildMode();
ResetCursor();
DisablePointer();
Wgo source = Source;
Source = null;
_def = null;
if ((Object)(object)source == (Object)null)
{
return;
}
try
{
WgoData data = source.Data;
WgoData placed = _placed;
List<Item> list = ((placed == null) ? null : ((!Plugin.CarryContents.Value) ? TakeFuel(data) : TakeInventory(data)));
_removed = data;
Detach(data);
ReleaseWorker(data);
DropEverything(source, data);
MainGame.Instance.GameSave.worldData.RemoveWgoDataFromGameScene(data, true);
Plugin.Log.LogInfo((object)"Move: the old building is gone");
FinishPlaced();
if (list != null)
{
PutInto(placed, list);
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Move: removing the old building failed: " + ex));
}
}
private static void FinishPlaced()
{
WgoData placed = _placed;
string replaceTo = _replaceTo;
_placed = null;
_replaceTo = null;
if (placed == null)
{
Plugin.Log.LogWarning((object)"Move: the placed building was not seen - links and icons are left as the game made them");
ClearExtensionIcons();
return;
}
try
{
WorldData worldData = MainGame.Instance.GameSave.worldData;
if (!string.IsNullOrEmpty(replaceTo) && ((ObjectLinkedToDefinition<WGODef>)(object)placed).id != replaceTo)
{
worldData.ChangeWgoData(placed, replaceTo);
Plugin.Log.LogInfo((object)("Move: the placed marker became " + replaceTo));
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not restore the building id: " + ex.Message));
}
Relink(placed);
_relink = placed;
ClearExtensionIcons();
StartIconSweep(placed);
}
private static void Relink(WgoData data)
{
if (data == null)
{
return;
}
Wgo val = null;
try
{
val = GameScene.GetWgoViewGlobal(data.UniqueId);
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not find the moved object: " + ex.Message));
}
if ((Object)(object)val == (Object)null)
{
return;
}
bool flag = false;
bool flag2 = false;
try
{
flag = GameBalance.Me.IsWorkbenchExtensionId(((ObjectLinkedToDefinition<WGODef>)(object)data).id);
}
catch (Exception ex2)
{
Plugin.Log.LogWarning((object)("Move: extension check failed: " + ex2.Message));
}
try
{
WGODef workbenchExtensionLogicDef = GameBalance.Me.GetWorkbenchExtensionLogicDef(((ObjectLinkedToDefinition<WGODef>)(object)data).id);
flag2 = workbenchExtensionLogicDef != null && workbenchExtensionLogicDef.attachedWorkbenchExtensionIds != null && workbenchExtensionLogicDef.attachedWorkbenchExtensionIds.Count > 0;
}
catch (Exception ex3)
{
Plugin.Log.LogWarning((object)("Move: workbench check failed: " + ex3.Message));
}
if (flag || flag2)
{
try
{
Physics.SyncTransforms();
}
catch
{
}
if (flag)
{
Attach(val, asWorkbench: false);
}
if (flag2)
{
Attach(val, asWorkbench: true);
}
if (flag)
{
RelinkNeighbours(val);
}
}
}
private static void RelinkNeighbours(Wgo view)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
try
{
Vector3 position = ((Component)view).transform.position;
Wgo[] array = Object.FindObjectsOfType<Wgo>();
foreach (Wgo val in array)
{
if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)view || val.Data == null)
{
continue;
}
Vector3 val2 = ((Component)val).transform.position - position;
if (!(((Vector3)(ref val2)).sqrMagnitude > 36f))
{
WGODef val3 = null;
try
{
val3 = GameBalance.Me.GetWorkbenchExtensionLogicDef(((ObjectLinkedToDefinition<WGODef>)(object)val.Data).id);
}
catch
{
}
if (val3 != null && val3.attachedWorkbenchExtensionIds != null && val3.attachedWorkbenchExtensionIds.Count != 0)
{
Attach(val, asWorkbench: true);
}
}
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not re-link the neighbours: " + ex.Message));
}
}
private static void Attach(Wgo view, bool asWorkbench)
{
string text = ((!asWorkbench) ? "extension" : "workbench");
try
{
HashSet<Wgo> hashSet = default(HashSet<Wgo>);
if (!SpecialPhysicsCastUtils.TryGetWgosIntersectedByBuffCollider(view, asWorkbench, ref hashSet) || hashSet == null)
{
Plugin.Log.LogInfo((object)("Move: nothing to link as " + text + " near " + ((ObjectLinkedToDefinition<WGODef>)(object)view.Data).id));
return;
}
foreach (Wgo item in hashSet)
{
if (!((Object)(object)item == (Object)null) && item.Data != null && item.Data != view.Data && !IsRemoved(item.Data))
{
if (asWorkbench)
{
item.Data.AddWorkbenchParent(view.Data.UniqueId);
view.Data.AddWorkbenchExtension(item.Data.UniqueId);
}
else
{
item.Data.AddWorkbenchExtension(view.Data.UniqueId);
view.Data.AddWorkbenchParent(item.Data.UniqueId);
}
Plugin.Log.LogInfo((object)("Move: linked " + ((ObjectLinkedToDefinition<WGODef>)(object)view.Data).id + " (" + text + ") with " + ((ObjectLinkedToDefinition<WGODef>)(object)item.Data).id));
}
}
ConditionalDrawer[] componentsInChildren = ((Component)view).GetComponentsInChildren<ConditionalDrawer>();
foreach (ConditionalDrawer val in componentsInChildren)
{
if ((Object)(object)val != (Object)null)
{
val.SubscribeToParentCraftStatusChanged(view.Data);
}
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not link as " + text + ": " + ex.Message));
}
}
private static int PruneDeadLinks(WgoData data)
{
int num = 0;
try
{
if (data == null)
{
return 0;
}
WorldData worldData = MainGame.Instance.GameSave.worldData;
IReadOnlyList<SGuid> attachedWorkbenchExtensions = data.AttachedWorkbenchExtensions;
if (attachedWorkbenchExtensions != null && attachedWorkbenchExtensions.Count > 0)
{
foreach (SGuid item in new List<SGuid>(attachedWorkbenchExtensions))
{
if (IsGone(worldData, item))
{
data.RemoveWorkbenchExtension(item);
num++;
}
}
}
IReadOnlyList<SGuid> workbenchParents = data.WorkbenchParents;
if (workbenchParents != null && workbenchParents.Count > 0)
{
foreach (SGuid item2 in new List<SGuid>(workbenchParents))
{
if (IsGone(worldData, item2))
{
data.RemoveWorkbenchParent(item2);
num++;
}
}
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not check old links: " + ex.Message));
}
return num;
}
private static bool IsRemoved(WgoData d)
{
try
{
return _removed != null && d != null && (d == _removed || d.UniqueId == _removed.UniqueId);
}
catch
{
return false;
}
}
private static bool IsGone(WorldData world, SGuid id)
{
if (id == (SGuid)null)
{
return false;
}
WgoData wgoData = world.GetWgoData(id);
return wgoData == null || IsRemoved(wgoData);
}
public static void TickBuildClosed()
{
bool flag = false;
try
{
BuildController val = Controller();
flag = (Object)(object)val != (Object)null && val.IsBuildModeActive;
}
catch
{
}
bool flag2 = _wasBuilding && !flag;
_wasBuilding = flag;
if (!flag2 || State != MoveState.Idle)
{
return;
}
Armed = false;
try
{
WorldData worldData = MainGame.Instance.GameSave.worldData;
int num = 0;
foreach (GameSceneData gameSceneData in worldData.gameSceneDataList)
{
if (gameSceneData == null || gameSceneData.wgoDataList == null)
{
continue;
}
foreach (WgoData wgoData in gameSceneData.wgoDataList)
{
if (wgoData != null && ((wgoData.AttachedWorkbenchExtensions != null && wgoData.AttachedWorkbenchExtensions.Count > 0) || (wgoData.WorkbenchParents != null && wgoData.WorkbenchParents.Count > 0)))
{
num += PruneDeadLinks(wgoData);
}
}
}
if (num > 0)
{
Plugin.Log.LogInfo((object)("Move: dropped " + num + " link(s) to buildings that are gone"));
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: link check skipped: " + ex.Message));
}
}
public static void TickRelink()
{
if (_relink != null)
{
WgoData relink = _relink;
_relink = null;
Relink(relink);
ClearExtensionIcons();
_removed = null;
}
TickIconSweep();
}
private static void StartIconSweep(WgoData placed)
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
try
{
Wgo val = ((placed == null) ? null : GameScene.GetWgoViewGlobal(placed.UniqueId));
if (!((Object)(object)val == (Object)null))
{
_sweepAt = ((Component)val).transform.position;
_sweepUntil = Time.unscaledTime + 1.5f;
}
}
catch
{
}
}
private static void TickIconSweep()
{
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
if (_sweepUntil < 0f)
{
return;
}
if (State != MoveState.Idle)
{
_sweepUntil = -1f;
return;
}
bool flag = false;
try
{
BuildController val = Controller();
flag = (Object)(object)val != (Object)null && val.IsBuildModeActive;
}
catch
{
}
if (!flag)
{
ClearExtensionIcons();
}
if (Time.unscaledTime < _sweepUntil)
{
return;
}
_sweepUntil = -1f;
if (flag)
{
return;
}
try
{
int num = 0;
Wgo[] array = Object.FindObjectsByType<Wgo>((FindObjectsSortMode)0);
foreach (Wgo val2 in array)
{
if ((Object)(object)val2 == (Object)null || val2.Data == null)
{
continue;
}
Vector3 val3 = ((Component)val2).transform.position - _sweepAt;
if (!(((Vector3)(ref val3)).sqrMagnitude > 36f))
{
try
{
val2.DrawWidgets();
num++;
}
catch
{
}
}
}
Plugin.Log.LogInfo((object)("Move: redrew the icons of " + num + " building(s) around the new spot"));
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not redraw the icons: " + ex.Message));
}
}
private static void ClearExtensionIcons()
{
try
{
WorkbenchAdditionWorldIconPresenter.Clear();
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not clear the extension icons: " + ex.Message));
}
}
private static void ReleaseWorker(WgoData data)
{
if (data == null)
{
return;
}
ZombieWgoData val = null;
try
{
IWorker worker = data.Worker;
val = (ZombieWgoData)(object)((worker is ZombieWgoData) ? worker : null);
}
catch
{
}
if (val != null)
{
try
{
val.UnAttachFromWgoData(false);
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not unattach the zombie: " + ex.Message));
}
try
{
Traverse val2 = Traverse.Create((object)val).Field("takenDockPointsParentSGuid");
SGuid value = val2.GetValue<SGuid>();
if (!SGuid.IsNullOrEmpty(value))
{
WgoData wgoData = MainGame.Instance.GameSave.WorldData.GetWgoData(value);
DockPointData val3 = ((wgoData == null || wgoData.MainWgoPartData == null) ? null : wgoData.MainWgoPartData.GetOccupiedDockPointBy(((WgoData)val).UniqueId));
if (val3 != null)
{
val3.UnOccupy();
}
val2.SetValue((object)null);
}
}
catch (Exception ex2)
{
Plugin.Log.LogWarning((object)("Move: could not free the zombie's spot: " + ex2.Message));
}
}
try
{
data.ClearWorker();
}
catch (Exception ex3)
{
Plugin.Log.LogWarning((object)("Move: could not free the worker: " + ex3.Message));
}
if (val == null)
{
return;
}
try
{
if (((WgoData)val).WorldZoneData != null)
{
((WgoData)val).WorldZoneData.NotifyWgoDataChanged();
}
}
catch
{
}
Plugin.Log.LogInfo((object)"Move: the zombie was let go and stays where it stood");
}
internal static BuildController Controller()
{
try
{
BuildController val = (BuildController)((!(_cachedController != null)) ? null : /*isinst with value type is only supported in some contexts*/);
if ((Object)(object)val != (Object)null)
{
return val;
}
return (State != MoveState.Idle) ? BuildController.Instance : null;
}
catch
{
return null;
}
}
private static void EndBuildMode()
{
try
{
BuildController val = Controller();
if ((Object)(object)val != (Object)null && val.IsBuildModeActive)
{
val.DisableBuildMode();
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not leave build mode: " + ex.Message));
}
try
{
BuildManager instance = LazySingleton<BuildManager>.Instance;
if ((Object)(object)instance != (Object)null)
{
instance.Disable();
}
}
catch (Exception ex2)
{
Plugin.Log.LogWarning((object)("Move: BuildManager.Disable failed: " + ex2.Message));
}
}
private static void DisablePointer()
{
try
{
BuildController val = Controller();
if (!((Object)(object)val == (Object)null))
{
BuildPointer value = Traverse.Create((object)val).Field("buildPointer").GetValue<BuildPointer>();
if ((Object)(object)value != (Object)null)
{
value.Disable();
}
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not clear the old pointer: " + ex.Message));
}
}
public static void ResetCursor()
{
try
{
CursorController.RemoveAllWithType((CursorType)2);
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not reset the cursor: " + ex.Message));
}
}
private static void DropEverything(Wgo old, WgoData data)
{
bool flag = false;
try
{
Traverse.Create((object)old).Method("DropItemsFromInventory", Array.Empty<object>()).GetValue();
flag = true;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not drop the inventory: " + ex.Message));
}
try
{
List<ItemCount> list = new List<ItemCount>();
DescribeHoldings(data);
CollectCrafts(data, list);
Collect((data == null) ? null : data.CraftInventory, "craft inventory", list);
if (!flag)
{
Collect((data == null) ? null : data.Inventory, "inventory", list);
}
Plugin.Log.LogInfo((object)("Move: dropping " + list.Count + " stack(s) from the craft slots" + ((!flag) ? " and the inventory" : "")));
if (list.Count > 0)
{
Traverse.Create((object)old).Method("DropItemsFromBuild", new object[1] { list }).GetValue();
}
if (data != null)
{
Empty(data.Inventory, "inventory");
if (list.Count > 0)
{
Empty(data.CraftInventory, "craft inventory");
}
}
}
catch (Exception ex2)
{
Plugin.Log.LogWarning((object)("Move: could not drop the craft slots: " + ex2.Message));
}
}
private static List<Item> TakeInventory(WgoData data)
{
try
{
Inventory val = ((data == null) ? null : data.Inventory);
if (val == null || val.Data == null || val.Data.Inventory == null || val.Data.Inventory.Count == 0)
{
return null;
}
List<Item> list = val.Data.RemoveAllItems();
if (list == null || list.Count == 0)
{
return null;
}
try
{
val.NotifyItemsRemoved(list);
}
catch
{
}
Plugin.Log.LogInfo((object)("Move: carrying " + list.Count + " stack(s) to the new spot: " + Describe(list)));
return list;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not lift the contents out (" + ex.Message + "), they will be dropped as usual"));
return null;
}
}
private static List<Item> TakeFuel(WgoData data)
{
try
{
Inventory val = ((data == null) ? null : data.Inventory);
if (val == null || val.Data == null || val.Data.Inventory == null)
{
return null;
}
List<Item> inventory = val.Data.Inventory;
List<Item> list = inventory.Where((Item i) => i != null && ((ObjectLinkedToDefinition<ItemDef>)(object)i).Definition != null && ((ObjectLinkedToDefinition<ItemDef>)(object)i).Definition.isFuel).ToList();
if (list.Count == 0)
{
return null;
}
foreach (Item item in list)
{
inventory.Remove(item);
}
try
{
val.NotifyItemsRemoved(list);
}
catch
{
}
Plugin.Log.LogInfo((object)("Move: carrying the fuel to the new spot: " + Describe(list)));
return list;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not lift the fuel out: " + ex.Message));
return null;
}
}
private static void PutInto(WgoData placed, List<Item> items)
{
if (items == null || items.Count == 0)
{
return;
}
try
{
Inventory val = ((placed == null) ? null : placed.Inventory);
if (val != null && val.CanAddItemsToInventory(items) && val.AddItemsToInventory(items))
{
Plugin.Log.LogInfo((object)"Move: the contents are in the new building");
return;
}
Plugin.Log.LogWarning((object)"Move: the new building would not take the contents - dropping them beside it");
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not put the contents back (" + ex.Message + ") - dropping them beside it"));
}
try
{
placed.MakeDrop(items);
}
catch (Exception ex2)
{
Plugin.Log.LogError((object)("Move: dropping the carried contents failed: " + ex2));
}
}
private static void Empty(Inventory inv, string what)
{
if (inv == null || inv.Data == null)
{
return;
}
List<Item> inventory = inv.Data.Inventory;
if (inventory == null || inventory.Count == 0)
{
return;
}
int count = inventory.Count;
try
{
inv.Clear();
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: Inventory.Clear failed (" + ex.Message + "), emptying the " + what + " list directly"));
try
{
inventory.Clear();
}
catch
{
}
}
Plugin.Log.LogInfo((object)("Move: " + what + " of the old building emptied (" + count + " entries)"));
}
private static void Collect(Inventory inv, string what, List<ItemCount> into)
{
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Expected O, but got Unknown
if (inv == null || inv.Data == null)
{
Plugin.Log.LogInfo((object)("Move: " + what + " is empty"));
return;
}
List<Item> inventory = inv.Data.Inventory;
if (inventory == null)
{
Plugin.Log.LogInfo((object)("Move: " + what + " holds nothing"));
return;
}
int num = 0;
foreach (Item item in inventory)
{
if (item != null && !item.IsEmpty)
{
string text = null;
try
{
text = Traverse.Create((object)item).Field("id").GetValue<string>();
}
catch
{
}
if (!string.IsNullOrEmpty(text) && item.Count > 0)
{
into.Add(new ItemCount(text, item.Count));
num++;
}
}
}
Plugin.Log.LogInfo((object)("Move: " + what + " -> " + num + " stack(s)"));
}
private static void CollectCrafts(WgoData data, List<ItemCount> into)
{
if (data == null)
{
return;
}
try
{
CraftComponent craftComponent = data.CraftComponent;
List<CraftElementBase> list = ((craftComponent == null) ? null : craftComponent.CraftElementsQueue);
if (list == null)
{
return;
}
foreach (CraftElementBase item in list)
{
if (item == null)
{
continue;
}
int count = into.Count;
bool flag = item.IsFinished;
try
{
flag = flag || (item.IsStarted && item.TotalProgressTicks > 0 && item.ProgressTicks >= item.TotalProgressTicks);
}
catch
{
}
if (flag)
{
AddCounts(Fld<List<ItemCount>>(item, "preOutputItems"), into);
AddCounts(Fld<List<ItemCount>>(item, "preToWgoOnFinishItems"), into);
AddItems(Fld<List<Item>>(item, "customCraftOutput"), into);
if (into.Count == count)
{
AddCounts(RecipeOutput(item, data), into);
}
AddLeftovers(item, data, into);
}
else
{
AddItems(Fld<List<Item>>(item, "craftInput"), into);
AddItems(Fld<List<Item>>(item, "customItems"), into);
}
Plugin.Log.LogInfo((object)("Move: " + item.CraftId + " (finished=" + item.IsFinished + ", canFinish=" + flag + ", started=" + item.IsStarted + ", ticks=" + item.ProgressTicks + "/" + item.TotalProgressTicks + ") -> " + (into.Count - count) + " stack(s)"));
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not empty the crafts: " + ex.Message));
}
}
private static void AddLeftovers(CraftElementBase ce, WgoData data, List<ItemCount> into)
{
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Expected O, but got Unknown
List<Item> list = Fld<List<Item>>(ce, "craftInput");
if (list == null)
{
return;
}
Dictionary<string, int> dictionary = new Dictionary<string, int>();
try
{
List<NeedItemData> requirements = ce.Requirements;
if (requirements != null)
{
foreach (NeedItemData item in requirements)
{
if (item != null && !string.IsNullOrEmpty(item.id))
{
int val = 0;
try
{
val = item.GetCount(data);
}
catch
{
}
dictionary[item.id] = (dictionary.TryGetValue(item.id, out var value) ? value : 0) + Math.Max(0, val);
}
}
}
}
catch
{
}
foreach (Item item2 in list)
{
if (item2 == null || item2.IsEmpty || item2.Count <= 0)
{
continue;
}
string text = Fld<string>(item2, "id");
if (!string.IsNullOrEmpty(text))
{
dictionary.TryGetValue(text, out var value2);
int num = item2.Count - value2;
if (value2 > 0)
{
dictionary[text] = 0;
}
if (num > 0)
{
into.Add(new ItemCount(text, num));
}
}
}
}
private static List<ItemCount> RecipeOutput(CraftElementBase ce, WgoData data)
{
try
{
CraftDefBase def = ce.Def;
OutputItems val = ((def == null) ? null : Traverse.Create((object)def).Field("outputItems").GetValue<OutputItems>());
if (val == null || !val.HasOutput())
{
return null;
}
return val.MakePreOutput((ICraftable)(object)data, 0f);
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not work out the craft result: " + ex.Message));
return null;
}
}
private static string Describe(Inventory inv)
{
try
{
return (inv == null || inv.Data == null) ? "none" : Describe(inv.Data.Inventory);
}
catch
{
return "?";
}
}
private static string Describe(List<Item> items)
{
if (items == null)
{
return "none";
}
string[] array = (from i in items
where i != null && !i.IsEmpty && i.Count > 0
select Fld<string>(i, "id") + "x" + i.Count).ToArray();
return (array.Length != 0) ? string.Join(", ", array) : "empty";
}
private static string Needs(CraftElementBase ce)
{
try
{
List<NeedItemData> requirements = ce.Requirements;
if (requirements == null)
{
return "none";
}
return string.Join(", ", (from n in requirements
where n != null
select n.id).ToArray());
}
catch
{
return "?";
}
}
private static T Fld<T>(object o, string name)
{
try
{
return Traverse.Create(o).Field(name).GetValue<T>();
}
catch
{
return default(T);
}
}
private static void AddItems(List<Item> items, List<ItemCount> into)
{
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Expected O, but got Unknown
if (items == null)
{
return;
}
foreach (Item item in items)
{
if (item != null && !item.IsEmpty && item.Count > 0)
{
string text = Fld<string>(item, "id");
if (!string.IsNullOrEmpty(text))
{
into.Add(new ItemCount(text, item.Count));
}
}
}
}
private static void AddCounts(List<ItemCount> items, List<ItemCount> into)
{
if (items == null)
{
return;
}
foreach (ItemCount item in items)
{
if (item != null && !item.IsEmpty)
{
into.Add(item);
}
}
}
private static void DescribeHoldings(WgoData data)
{
if (data == null)
{
return;
}
try
{
CraftComponent craftComponent = data.CraftComponent;
if (craftComponent == null)
{
Plugin.Log.LogInfo((object)"Move: no craft component");
return;
}
CraftElementBase currentCraftElement = craftComponent.CurrentCraftElement;
List<CraftElementBase> craftElementsQueue = craftComponent.CraftElementsQueue;
Plugin.Log.LogInfo((object)("Move: craft current=" + ((currentCraftElement == null) ? "-" : currentCraftElement.CraftId) + " queue=" + (craftElementsQueue?.Count ?? 0) + " | inventory: " + Describe(data.Inventory) + " | craft inventory: " + Describe(data.CraftInventory)));
if (craftElementsQueue == null)
{
return;
}
foreach (CraftElementBase item in craftElementsQueue)
{
if (item == null)
{
continue;
}
Plugin.Log.LogInfo((object)("Move: " + item.CraftId + " input=" + Describe(Fld<List<Item>>(item, "craftInput")) + " needs=" + Needs(item)));
string text = "?";
try
{
List<Item> value = Traverse.Create((object)item).Field("customOutputItems").GetValue<List<Item>>();
text = ((value != null) ? string.Join(", ", (from i in value
where i != null && !i.IsEmpty
select Traverse.Create((object)i).Field("id").GetValue<string>() + "x" + i.Count).ToArray()) : "none");
}
catch (Exception ex)
{
text = "err " + ex.Message;
}
Plugin.Log.LogInfo((object)("Move: queued " + item.CraftId + " output=" + text));
}
}
catch (Exception ex2)
{
Plugin.Log.LogWarning((object)("Move: could not inspect the crafts: " + ex2.Message));
}
}
private static void Detach(WgoData data)
{
if (data == null)
{
return;
}
try
{
WorldData worldData = MainGame.Instance.GameSave.worldData;
foreach (SGuid item in new List<SGuid>(data.AttachedWorkbenchExtensions ?? new List<SGuid>()))
{
Wgo wgoViewGlobal = GameScene.GetWgoViewGlobal(item);
if ((Object)(object)wgoViewGlobal != (Object)null && wgoViewGlobal.Data != null)
{
wgoViewGlobal.Data.RemoveWorkbenchParent(data.UniqueId);
}
data.RemoveWorkbenchExtension(item);
}
foreach (SGuid item2 in new List<SGuid>(data.WorkbenchParents ?? new List<SGuid>()))
{
Wgo wgoViewGlobal2 = GameScene.GetWgoViewGlobal(item2);
if ((Object)(object)wgoViewGlobal2 != (Object)null && wgoViewGlobal2.Data != null)
{
wgoViewGlobal2.Data.RemoveWorkbenchExtension(data.UniqueId);
}
data.RemoveWorkbenchParent(item2);
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not detach workbench links: " + ex.Message));
}
}
public static void OnBuildModeEntered(BuildData data)
{
Armed = IsMoveEntry(data);
}
public static void Cancel(string why)
{
ClearExtensionIcons();
if (Active)
{
Plugin.Log.LogInfo((object)("Move cancelled: " + why));
}
State = MoveState.Idle;
Armed = false;
Source = null;
_def = null;
ResetCursor();
}
}
[BepInPlugin("gk2.movebuilding", "GK2 Move Buildings", "0.4.15")]
public sealed class Plugin : BaseUnityPlugin
{
public const string Guid = "gk2.movebuilding";
public const string Version = "0.4.15";
internal static ManualLogSource Log;
internal static Plugin Instance;
private float _buildModeSeenAt;
internal static ConfigEntry<KeyboardShortcut> MoveModifier;
internal static ConfigEntry<bool> DropWorker;
internal static ConfigEntry<bool> CarryContents;
internal static ConfigEntry<string> MoveIconId;
private void Awake()
{
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Expected O, but got Unknown
//IL_05c7: Unknown result type (might be due to invalid IL or missing references)
//IL_05cc: Unknown result type (might be due to invalid IL or missing references)
//IL_05d0: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Expected O, but got Unknown
//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
//IL_01cc: Expected O, but got Unknown
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
//IL_022e: Expected O, but got Unknown
//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
//IL_02d7: Expected O, but got Unknown
//IL_031c: Unknown result type (might be due to invalid IL or missing references)
//IL_032a: Expected O, but got Unknown
//IL_0365: Unknown result type (might be due to invalid IL or missing references)
//IL_036c: Expected O, but got Unknown
//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
//IL_03bb: Expected O, but got Unknown
//IL_0403: Unknown result type (might be due to invalid IL or missing references)
//IL_040a: Expected O, but got Unknown
//IL_057b: Unknown result type (might be due to invalid IL or missing references)
//IL_0582: Expected O, but got Unknown
//IL_04e0: Unknown result type (might be due to invalid IL or missing references)
//IL_04e7: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Instance = this;
MoveIconId = ((BaseUnityPlugin)this).Config.Bind<string>("General", "MoveIcon", "", Cm.D("Sprite name for the Move button. Empty picks one automatically; the log lists the candidates.", "Move button icon (sprite name)", 0, advanced: true, null, browsable: false));
DropWorker = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PutWorkerDown", true, Cm.D("No longer used: a zombie working in a moved building is always let go where it stood (0.4.15).", "Put the zombie down", 20, advanced: false, null, browsable: false));
CarryContents = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CarryContents", false, Cm.D("Chests, racks and shelves keep their contents when moved, instead of dropping them on the ground. Things loaded into a station's crafts still come out on the ground.", "Carry the contents", 30));
MoveModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Hotkeys", "MoveModifier", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), Cm.D("Hold this in the game's remove mode and click a building to move it instead of demolishing it.", "Move modifier (hold in remove mode)", 10));
try
{
Harmony val = new Harmony("gk2.movebuilding");
MethodInfo methodInfo = AccessTools.Method(typeof(Wgo), "DoBuildRemove", (Type[])null, (Type[])null);
if (methodInfo != null)
{
val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Plugin), "RemovePre", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
else
{
Log.LogError((object)"Wgo.DoBuildRemove not found - remove actions cannot be intercepted");
}
ConstructorInfo constructorInfo = AccessTools.Constructor(typeof(UIBuildingWindowData), new Type[6]
{
typeof(Wgo),
typeof(PlayerData),
typeof(List<BuildData>),
typeof(Action<BuildData, List<NeedItemData>>),
typeof(Func<BuildData, List<NeedItemData>, bool>),
typeof(List<Inventory>)
}, false);
if (constructorInfo != null)
{
ConstructorInfo constructorInfo2 = constructorInfo;
HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin), "WindowDataPost", (Type[])null);
val.Patch((MethodBase)constructorInfo2, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
else
{
Log.LogWarning((object)"Build window data constructor not found - there will be no Move button");
}
MethodInfo methodInfo2 = AccessTools.Method(typeof(UIBuildingWidget), "Redraw", (Type[])null, (Type[])null);
if (methodInfo2 != null)
{
MethodInfo methodInfo3 = methodInfo2;
HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin), "WidgetRedrawPost", (Type[])null);
val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
ConstructorInfo constructorInfo3 = AccessTools.Constructor(typeof(UIBuildingWidgetData), new Type[7]
{
typeof(BuildData),
typeof(MultiInventory),
typeof(Action<BuildData, List<NeedItemData>>),
typeof(Func<BuildData, List<NeedItemData>, bool>),
typeof(Action),
typeof(Action),
typeof(WorldZoneData)
}, false);
if (constructorInfo3 != null)
{
ConstructorInfo constructorInfo2 = constructorInfo3;
HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin), "WidgetDataPost", (Type[])null);
val.Patch((MethodBase)constructorInfo2, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
MethodInfo methodInfo4 = AccessTools.Method(typeof(BuildManager), "EnableBuildMode", (Type[])null, (Type[])null);
if (methodInfo4 != null)
{
val.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(Plugin), "EnableBuildModePre", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
MethodInfo methodInfo5 = AccessTools.Method(typeof(WgoBuildPointer), "SetTarget", (Type[])null, (Type[])null);
if (methodInfo5 != null)
{
MethodInfo methodInfo3 = methodInfo5;
HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin), "SetTargetPost", (Type[])null);
val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
MethodInfo methodInfo6 = AccessTools.Method(typeof(WgoBuildPointer), "TryDoBuildAction", (Type[])null, (Type[])null);
if (methodInfo6 != null)
{
MethodInfo methodInfo3 = methodInfo6;
HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin), "BuildActionPost", (Type[])null);
val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
MethodInfo methodInfo7 = AccessTools.Method(typeof(BuildSelectionCell), "OverlapBoxNonAlloc", (Type[])null, (Type[])null);
if (methodInfo7 != null)
{
MethodInfo methodInfo3 = methodInfo7;
HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin), "OverlapPost", (Type[])null);
val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
else
{
Log.LogWarning((object)"BuildSelectionCell.OverlapBoxNonAlloc not found - a moved building will block its own old spot");
}
int num = 0;
Type[] array = new Type[2]
{
typeof(GameScene),
typeof(WorldData)
};
foreach (Type type in array)
{
foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type))
{
if (!(declaredMethod.Name != "AddWgoData"))
{
ParameterInfo[] parameters = declaredMethod.GetParameters();
if (parameters.Length != 0 && !(parameters[0].ParameterType != typeof(WgoData)))
{
MethodInfo methodInfo3 = declaredMethod;
HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin), "AddWgoPost", (Type[])null);
val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
num++;
}
}
}
}
if (num == 0)
{
Log.LogWarning((object)"AddWgoData not found - two-step buildings and extensions will not be fixed up");
}
MethodInfo methodInfo8 = AccessTools.Method(typeof(BuildController), "UpdateFullCoverSoftBuildAreaHints", (Type[])null, (Type[])null);
if (methodInfo8 != null)
{
MethodInfo methodInfo3 = methodInfo8;
HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin), "HintsFinalizer", (Type[])null);
val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null);
}
}
catch (Exception ex)
{
Log.LogError((object)("Patch failed: " + ex));
}
Framework.TryRegister((BaseUnityPlugin)(object)this);
ManualLogSource log = Log;
KeyboardShortcut value = MoveModifier.Value;
log.LogInfo((object)string.Concat("GK2 Move Buildings 0.4.15 loaded (hold ", ((KeyboardShortcut)(ref value)).MainKey, " in remove mode to move a building)"));
}
private void Update()
{
try
{
Move.TickRelink();
Move.TickAbort();
Move.TickRescue();
if (Move.State == MoveState.Pending)
{
_buildModeSeenAt = Time.unscaledTime;
Move.StartPlacing();
return;
}
Move.TickBuildClosed();
if (Move.Active)
{
if (InBuildMode())
{
_buildModeSeenAt = Time.unscaledTime;
}
if (Time.unscaledTime - _buildModeSeenAt > 1f)
{
Move.Cancel("build mode has been closed for a second");
}
}
}
catch
{
}
}
private static bool InBuildMode()
{
try
{
BuildController val = Move.Controller();
return (Object)(object)val != (Object)null && val.IsBuildModeActive;
}
catch
{
return false;
}
}
private static void WindowDataPost(object __instance)
{
Ui.AddMoveEntry(__instance);
}
private static void WidgetDataPost(object __instance, BuildData buildData)
{
Ui.RenameMoveWidget(__instance, buildData);
}
private static void WidgetRedrawPost(object __instance)
{
Ui.ApplyIcon(__instance);
}
private static void EnableBuildModePre(BuildData selectedBuildData)
{
Move.OnBuildModeEntered(selectedBuildData);
}
private static void SetTargetPost(WgoBuildPointer __instance)
{
if (!Move.RefuseSpecialPointer(__instance))
{
Move.MakeFree(__instance);
}
}
private static void OverlapPost(Collider[] overlapColliders, ref int __result)
{
Move.FilterOwnColliders(overlapColliders, ref __result);
}
private static void AddWgoPost(object[] __args)
{
WgoData data = (WgoData)((__args == null || __args.Length <= 0) ? null : /*isinst with value type is only supported in some contexts*/);
Move.OnWgoAdded(data);
}
private static Exception HintsFinalizer(Exception __exception)
{
if (__exception is NullReferenceException && Move.JustFinished)
{
return null;
}
return __exception;
}
private static void BuildActionPost(bool __result)
{
if (__result)
{
Move.Finish();
}
}
private static bool RemovePre(Wgo __instance, ref bool __result)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
if (!Move.Armed)
{
KeyboardShortcut value = MoveModifier.Value;
if (!Input.GetKey(((KeyboardShortcut)(ref value)).MainKey))
{
return true;
}
}
if (Move.TryPickUp(__instance))
{
__result = false;
return false;
}
Log.LogWarning((object)("Move: " + __instance.Id + " cannot be moved - the click is ignored, nothing is removed"));
Ui.SayCannotMove();
__result = false;
return false;
}
}
internal static class Ui
{
private static readonly string[] Langs = new string[11]
{
"en", "ru", "de", "fr", "es", "pt-br", "pl", "tr", "ja", "zh_cn",
"ko"
};
private static readonly string[] MoveText = new string[11]
{
"Move", "Переместить", "Verschieben", "Déplacer", "Mover", "Mover", "Przenieś", "Taşı", "移動", "移动",
"이동"
};
private static readonly string[] CannotMoveText = new string[11]
{
"This one can't be moved.", "Это не перенести.", "Das lässt sich nicht verschieben.", "Impossible de déplacer ceci.", "Esto no se puede mover.", "Isso não pode ser movido.", "Tego nie da się przenieść.", "Bu taşınamaz.", "これは移動できない。", "这个没法移动。",
"이건 옮길 수 없다."
};
private static Sprite _icon;
private static bool _iconSearched;
private static Texture2D _iconTexture;
private static float _fittedWidth = -1f;
private static int _iconTries;
private static string Pick(string[] table)
{
string lang = null;
try
{
lang = LLBase.CurrentLang;
}
catch
{
}
int num = Array.IndexOf(Langs, lang ?? "en");
if (num < 0 && lang != null && lang.Length >= 2)
{
num = Array.FindIndex(Langs, (string l) => l.StartsWith(lang.Substring(0, 2)));
}
return table[(num >= 0) ? num : 0];
}
public static void SayCannotMove()
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
try
{
Bubble.Talk(new PhraseData(true, (WgoData)null, Pick(CannotMoveText), (Action)null, (SpeechBubblePreset)null, (SpeechBubbleType)0, (ForceCornerPosition)0, 0f, false));
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not show the hint: " + ex.Message));
}
}
public static string MoveLabel()
{
string lang = null;
try
{
lang = LLBase.CurrentLang;
}
catch
{
}
int num = Array.IndexOf(Langs, lang ?? "en");
if (num < 0 && lang != null && lang.Length >= 2)
{
num = Array.FindIndex(Langs, (string l) => l.StartsWith(lang.Substring(0, 2)));
}
return MoveText[(num >= 0) ? num : 0];
}
public static void AddMoveEntry(object windowData)
{
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Invalid comparison between Unknown and I4
try
{
Dictionary<string, List<BuildData>> value = Traverse.Create(windowData).Property("TabSortedBuilds", (object[])null).GetValue<Dictionary<string, List<BuildData>>>();
if (value == null)
{
return;
}
BuildData item = Move.NewEntry();
foreach (List<BuildData> value2 in value.Values)
{
if (value2 == null)
{
continue;
}
bool flag = false;
foreach (BuildData item2 in value2)
{
if (item2 != null && (int)item2.BuildingMode == 2)
{
flag = true;
break;
}
}
if (flag)
{
value2.Add(item);
}
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move button: " + ex.Message));
}
}
public static Sprite MoveIcon()
{
if (_iconSearched)
{
return _icon;
}
_iconSearched = true;
_icon = LoadOwnIcon();
if ((Object)(object)_icon != (Object)null)
{
return _icon;
}
try
{
EasySpritesCollection instance = LazySingletonSO<EasySpritesCollection>.Instance;
string text = ((Plugin.MoveIconId == null) ? null : Plugin.MoveIconId.Value);
if (!string.IsNullOrEmpty(text))
{
_icon = instance.GetSprite(text, (string)null);
if ((Object)(object)_icon == (Object)null)
{
Plugin.Log.LogWarning((object)("Move: no sprite named " + text));
}
return _icon;
}
Dictionary<string, string> value = Traverse.Create((object)instance).Field("hash").GetValue<Dictionary<string, string>>();
if (value == null)
{
return null;
}
List<string> list = (from n in value.Keys
where n.IndexOf("move", StringComparison.OrdinalIgnoreCase) >= 0 || n.IndexOf("arrow", StringComparison.OrdinalIgnoreCase) >= 0
orderby (n.IndexOf("move", StringComparison.OrdinalIgnoreCase) < 0) ? 1 : 0, n.Length
select n).ToList();
Plugin.Log.LogInfo((object)("Move: icon candidates: " + string.Join(", ", list.Take(40).ToArray())));
foreach (string item in list)
{
_icon = instance.GetSprite(item, (string)null);
if ((Object)(object)_icon != (Object)null)
{
Plugin.Log.LogInfo((object)("Move: using icon " + item));
break;
}
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not pick an icon: " + ex.Message));
}
return _icon;
}
private static Sprite FitIcon(Sprite current)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)current == (Object)null)
{
return null;
}
Rect rect = current.rect;
float num = ((Rect)(ref rect)).width / current.pixelsPerUnit;
if ((Object)(object)_icon != (Object)null && Mathf.Approximately(num, _fittedWidth))
{
return _icon;
}
if ((Object)(object)_iconTexture == (Object)null)
{
MoveIcon();
if ((Object)(object)_iconTexture == (Object)null)
{
return null;
}
}
try
{
float num2 = (float)((Texture)_iconTexture).width / Mathf.Max(0.0001f, num);
_icon = Sprite.Create(_iconTexture, new Rect(0f, 0f, (float)((Texture)_iconTexture).width, (float)((Texture)_iconTexture).height), new Vector2(0.5f, 0.5f), num2);
_fittedWidth = num;
Plugin.Log.LogInfo((object)("Move: icon fitted to " + num + " units (" + num2 + " px per unit)"));
return _icon;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not resize the icon: " + ex.Message));
return null;
}
}
private static Sprite LoadOwnIcon()
{
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Expected O, but got Unknown
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
try
{
string directoryName = Path.GetDirectoryName(typeof(Ui).Assembly.Location);
string path = Path.Combine(directoryName ?? ".", "move_icon.png");
if (!File.Exists(path))
{
Plugin.Log.LogInfo((object)"Move: no move_icon.png next to the DLL");
return null;
}
Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
((Texture)val).filterMode = (FilterMode)0;
if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path)))
{
return null;
}
_iconTexture = val;
Sprite result = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
Plugin.Log.LogInfo((object)"Move: using the bundled icon");
return result;
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not load move_icon.png: " + ex.Message));
return null;
}
}
public static void ApplyIcon(object widget)
{
try
{
object value = Traverse.Create(widget).Field("data").GetValue();
BuildData val = ((value == null) ? null : Traverse.Create(value).Property("BuildData", (object[])null).GetValue<BuildData>());
if (_iconTries < 3)
{
_iconTries++;
Plugin.Log.LogInfo((object)("Move: widget redraw, data=" + (value != null) + " build=" + (val != null) + " ours=" + Move.IsMoveEntry(val)));
}
if (!Move.IsMoveEntry(val))
{
return;
}
Image value2 = Traverse.Create(widget).Field("resultIcon").GetValue<Image>();
if (!((Object)(object)value2 == (Object)null))
{
Sprite val2 = FitIcon(value2.sprite) ?? MoveIcon();
if ((Object)(object)val2 != (Object)null)
{
value2.sprite = val2;
}
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move: could not set the icon: " + ex.Message));
}
}
public static void RenameMoveWidget(object widgetData, BuildData buildData)
{
if (!Move.IsMoveEntry(buildData))
{
return;
}
try
{
Traverse.Create(widgetData).Property("Name", (object[])null).SetValue((object)MoveLabel());
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Move button label: " + ex.Message));
}
}
}
}