Decompiled source of CardShopCoop v1.0.37
CardShopCoop.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using CC; using CardShopCoop.Net; using CardShopCoop.Patches; using CardShopCoop.Sync; using CardShopCoop.UI; using CardShopCoop.Util; using HarmonyLib; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("CardShopCoop")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.37.0")] [assembly: AssemblyInformationalVersion("1.0.37+dd37610e424c21f00c01126ab0e098dd73f7733e")] [assembly: AssemblyProduct("CardShopCoop")] [assembly: AssemblyTitle("CardShopCoop")] [assembly: AssemblyVersion("1.0.37.0")] namespace CardShopCoop { public enum CoopRole { None, Host, Client } public class CoopCore : MonoBehaviour { private struct HeldPurchase { public InMsg Msg; public double At; } private struct ChargeVerdict { public bool Accepted; public double At; } private struct PendingCard { public bool IsAdd; public int Amount; public CardData Card; } private struct MyCardPrice { public CardData Card; public float Value; public bool Acked; public double LastSend; public int Attempts; } private struct MyItemPrice { public float Value; public double At; } private enum PurchaseGate { Process, Drop, Hold } public static bool GuestBorrowedWorld; public static bool HostServeKeyEnabled = false; public string StatusLine = "Not connected"; public string ErrorLine = ""; public string HostTimeLine = ""; public string RegisterLine = ""; public float RegisterLineTimer; private float _serveThrottle; public readonly Dictionary<int, string> PeerNames = new Dictionary<int, string>(); private ICoopTransport _net; private readonly SteamLobby _steamLobby = new SteamLobby(); private ulong _autoJoinSteamLobby; private readonly AvatarManager _avatars = new AvatarManager(); private readonly WorldSync _world = new WorldSync(); private readonly NpcSync _npcs = new NpcSync(); private readonly CardShelfSync _cardShelves = new CardShelfSync(); private readonly ObjMoveSync _objMoves = new ObjMoveSync(); private readonly BoxSync _boxes = new BoxSync(); private readonly PopulationSync _population = new PopulationSync(); private readonly GradingSync _grading = new GradingSync(); private readonly TradeServe _trades = new TradeServe(); private readonly PlayTableSync _tables = new PlayTableSync(); private readonly StaffSync _staff = new StaffSync(); private readonly ShopStateSync _shopState = new ShopStateSync(); private readonly SettingsSync _settings = new SettingsSync(); private readonly MarketSync _market = new MarketSync(); private readonly ReportSync _report = new ReportSync(); private readonly ContainerSync _containers = new ContainerSync(); private readonly TournamentSync _tournament = new TournamentSync(); private readonly CardBoxSync _cardBoxes = new CardBoxSync(); private readonly FurnBoxSync _furnBoxes = new FurnBoxSync(); private string _lastShopNameSent; private float _shopNameTimer = -1f; private readonly RegisterMirror _registerMirror = new RegisterMirror(); private float _npcSweepTimer = -1.3f; private float _regStateTimer = -0.17f; public string PromptLine = ""; private readonly ConcurrentQueue<Action> _mainThread = new ConcurrentQueue<Action>(); private CoopUI _ui; private MemoryStream _saveBuf; private int _saveExpected = -1; private byte[] _pendingSave; private MemoryStream _bundleBuf; private int _bundleExpected = -1; private int _hostSlot; private bool _worldRequested; private float _priceTimer = -0.45f; private int _lastPriceHash; private float _priceHeal; private readonly List<KeyValuePair<int, float>> _priceBuf = new List<KeyValuePair<int, float>>(); private readonly HashSet<int> _priceSeenTypes = new HashSet<int>(); private float _stateTimer; private float _pingTimer; private float _econTimer = -0.11f; private float _dayTimer = -0.9f; private Vector3 _lastPos; private bool _hasLastPos; private double _lastCoinSent = double.MinValue; private long _lastProgressSent = long.MinValue; private float _coinHeal; private float _progressHeal; private double _pendingReduceThisFrame; private readonly List<HeldPurchase> _heldPurchases = new List<HeldPurchase>(); private bool _deliveringHeld; private readonly Dictionary<int, ChargeVerdict> _chargeVerdicts = new Dictionary<int, ChargeVerdict>(); private const double VerdictTtl = 1.0; private const double VerdictDeclineTtl = 10.0; private readonly Dictionary<int, double> _lastDeclineToast = new Dictionary<int, double>(); private readonly HashSet<int> _gotStateFrom = new HashSet<int>(); private bool _loggedEconLink; private bool _loggedTimeLink; private long _diagSent; private long _diagRecvStates; private float _diagTimer = -7.3f; private float _errLogCooldown; private static readonly FieldInfo FiTimeHour = typeof(LightManager).GetField("m_TimeHour", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo FiTimeMin = typeof(LightManager).GetField("m_TimeMin", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo FiTimeMinFloat = typeof(LightManager).GetField("m_TimeMinFloat", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo FiHasDayEnded = typeof(LightManager).GetField("m_HasDayEnded", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo MiDayReset = typeof(LightManager).GetMethod("DelayUpdateEnv", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo FiTimeOfDayIdx = typeof(LightManager).GetField("m_TImeOfDayIndex", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo FiFinishLoading = typeof(LightManager).GetField("m_FinishLoading", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo MiLightInit = typeof(LightManager).GetMethod("Init", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo MiUpdateLightData = typeof(LightManager).GetMethod("UpdateLightTimeData", BindingFlags.Instance | BindingFlags.NonPublic); private float _lightSyncTimer = -2.3f; private LightManager _lightManager; private float _cardResyncTimer = -5.2f; private int _lastCardResyncHash; private float _cardResyncHeal; private float _cardPriceHealTimer = -2.1f; private int _lastCardPriceHash; private float _cardPriceHealBeat; private int _lastStockResyncHash; private float _stockResyncHeal; private readonly List<KeyValuePair<CardData, float>> _cardPriceBuf = new List<KeyValuePair<CardData, float>>(); private float _licenseSyncTimer = -3.7f; private double _lastLicenseBuyTime = -999.0; private string _lastLightJson; private float _lightHeal; private double _lastDayMirrorAt = -999.0; private int _lastLicenseHash; private float _licenseHeal; private float _dt; private bool _syncActive; private Action _actNetPump; private Action _actAvatars; private Action _actWorld; private Action _actCardShelves; private Action _actObjMoves; private Action _actBoxes; private Action _actPopulation; private Action _actNpcPuppets; private Action _actRegisterMirror; private Action _actNpcSweep; private Action _actStateSend; private Action _actNpcCollect; private Action _actRegisterCollect; private Action _actModules; private Action _actCardPriceRetry; private Action _actFrameCardWork; private CustomerManager _cmSweep; private CustomerManager _cmSpray; private bool _renamerHandled; private TMP_Text _shopSign; private string _lastShopNameApplied; private int _heldBoxFrame = -1; private object _heldBoxA; private object _heldBoxB; private object _heldBoxC; public static bool ClientReloading; private float _reloadGrace; private readonly List<InMsg> _dispatchBuf = new List<InMsg>(64); private readonly HashSet<long> _dispatchSeen = new HashSet<long>(); private const int DispatchBudget = 256; private int _autoHostSlot = -1; private string _autoJoinIp; private int _autoPhase; private float _autoTimer; private static bool _enumLendWarned; public string HostPassword = ""; private string _joinPassword = ""; public CSteamID LastFailedLobby = CSteamID.Nil; private const int EnumBlobCap = 262144; private readonly Dictionary<string, int> _enumSyncSentTo = new Dictionary<string, int>(); private readonly Dictionary<string, int> _enumSyncSentToPeer = new Dictionary<string, int>(); private const int EnumSyncMaxSends = 2; private const int EnumSyncMaxSendsPerPeer = 5; private readonly List<KeyValuePair<int, float>> _pendingKicks = new List<KeyValuePair<int, float>>(); private readonly List<PendingCard> _pendingCardDeltas = new List<PendingCard>(); private readonly List<KeyValuePair<CardData, float>> _pendingCardPrices = new List<KeyValuePair<CardData, float>>(); private readonly List<PendingCard> _cardDeltaOutbox = new List<PendingCard>(); private const int CardDeltaBatchMax = 200; private bool _flushingCardDeltas; private readonly List<PendingCard> _batchRelayBuf = new List<PendingCard>(); private static bool _binderRefreshPending; private static readonly List<PendingCard> _deltaLogBuf = new List<PendingCard>(); private static int _deltaAppliedThisFrame; private readonly Dictionary<string, MyCardPrice> _myCardPrices = new Dictionary<string, MyCardPrice>(); private readonly List<string> _cardPriceRetryKeys = new List<string>(); private float _cardPriceRetryTimer; private const int MyCardPriceMax = 1024; private const int CardPriceMaxAttempts = 12; private const float CardPriceEpsilon = 0.0075f; private readonly Dictionary<int, MyItemPrice> _myItemPriceEdits = new Dictionary<int, MyItemPrice>(); private const int MyItemPriceMax = 256; private const double ItemPriceHoldSeconds = 6.0; private static InteractionPlayerController _deltaIpc; private static readonly Dictionary<ECardExpansionType, HashSet<EMonsterType>> _shownMonsters = new Dictionary<ECardExpansionType, HashSet<EMonsterType>>(); private static readonly HashSet<string> _priceWarnedKeys = new HashSet<string>(); private static readonly MethodInfo MiBinderResort = AccessTools.Method(typeof(CollectionBinderFlipAnimCtrl), "OnSortingMethodUpdated", (Type[])null, (Type[])null); private static readonly FieldInfo FiBinderIsBookOpen = AccessTools.Field(typeof(CollectionBinderFlipAnimCtrl), "m_IsBookOpen"); private static readonly FieldInfo FiBinderUI = AccessTools.Field(typeof(CollectionBinderFlipAnimCtrl), "m_CollectionBinderUI"); private static readonly FieldInfo FiBinderIsGradedAlbum = AccessTools.Field(typeof(CollectionBinderFlipAnimCtrl), "m_IsGradedCardAlbum"); private static readonly FieldInfo FiBinderExpansionType = AccessTools.Field(typeof(CollectionBinderFlipAnimCtrl), "m_ExpansionType"); private int _selfId = -1; private readonly HashSet<int> _relayIds = new HashSet<int>(); private static InventoryBase _inventory; private Transform _playerTf; private Transform _playerCamTf; private InteractionPlayerController _playerIpc; private static readonly FieldInfo FiHoldBox = AccessTools.Field(typeof(InteractionPlayerController), "m_CurrentHoldingBox"); private static readonly FieldInfo FiHoldItemBox = AccessTools.Field(typeof(InteractionPlayerController), "m_CurrentHoldingItemBox"); private static readonly FieldInfo FiHoldBoxShelf = AccessTools.Field(typeof(InteractionPlayerController), "m_CurrentHoldingBoxShelf"); private static readonly FieldInfo FiHoldBoxCard = AccessTools.Field(typeof(InteractionPlayerController), "m_CurrentHoldingBoxCard"); private static readonly FieldInfo FiHoldItemList = AccessTools.Field(typeof(InteractionPlayerController), "m_HoldItemList"); private static readonly FieldInfo FiIsHoldBoxMode = AccessTools.Field(typeof(InteractionPlayerController), "m_IsHoldBoxMode"); private readonly List<int> _holdTypesBuf = new List<int>(6); private readonly List<CardData> _holdCardsBuf = new List<CardData>(4); private static readonly FieldInfo FiHoldCard3dList = AccessTools.Field(typeof(InteractionPlayerController), "m_CurrentHoldingCard3dList"); private static readonly FieldInfo FiViewAlbum = AccessTools.Field(typeof(InteractionPlayerController), "m_IsViewCardAlbumMode"); private static bool _eplProbed; private static PropertyInfo _eplAssetsProp; private static PropertyInfo _eplItemLibProp; private static PropertyInfo _eplRestockProp; private static readonly FieldInfo FiPanelIndex = AccessTools.Field(typeof(RestockItemPanelUI), "m_Index"); private static readonly FieldInfo FiPanelLicGrp = AccessTools.Field(typeof(RestockItemPanelUI), "m_LicenseUIGrp"); private static readonly FieldInfo FiPanelUIGrp = AccessTools.Field(typeof(RestockItemPanelUI), "m_UIGrp"); private bool _catalogSent; private float _catalogTimer; private int _lastCatalogSentHash; private readonly HashSet<int> _catalogWarnedConns = new HashSet<int>(); private readonly Dictionary<int, string> _rosterNames = new Dictionary<int, string>(); private HashSet<int> _clientPriced = new HashSet<int>(); private HashSet<int> _incomingPriced = new HashSet<int>(); public static CoopCore Instance { get; private set; } public static CoopRole Role { get; private set; } = CoopRole.None; public bool IsSteamSession { get; private set; } private bool ClientPreloadHold { get { if (ClientReloading) { return _reloadGrace <= 0f; } return false; } } public SteamLobby Lobby => _steamLobby; private void Guarded(string stage, Action action) { try { action(); } catch (Exception arg) { if (_errLogCooldown <= 0f) { _errLogCooldown = 5f; CoopPlugin.Log.LogError((object)$"[{stage}] {arg}"); } } } private static int DispatchCost(InMsg m) { if (m.Type != MsgType.CardDeltaBatch) { return 1; } byte[] payload = m.Payload; if (payload == null || payload.Length < 4) { return 1; } int num = payload[0] | (payload[1] << 8) | (payload[2] << 16) | (payload[3] << 24); if (num < 1) { return 1; } if (num <= 200) { return num; } return 200; } private unsafe void Awake() { Instance = this; _ui = new CoopUI(); _world.OnLocalChanges = OnLocalWorldChanges; _cardShelves.OnLocalChanges = delegate(List<CardShelfSync.Entry> changes) { if (Role == CoopRole.Host) { Broadcast(MsgType.CardShelfDelta, delegate(BinaryWriter bw) { CardShelfSync.WriteEntries(bw, changes); }); } else if (Role == CoopRole.Client) { Send(1, MsgType.CardShelfRequest, delegate(BinaryWriter bw) { CardShelfSync.WriteEntries(bw, changes); }); } }; _objMoves.OnLocalChanges = delegate(List<ObjMoveSync.Entry> changes) { if (Role == CoopRole.Host) { Broadcast(MsgType.ObjMoveDelta, delegate(BinaryWriter bw) { ObjMoveSync.WriteEntries(bw, changes); }); } else if (Role == CoopRole.Client) { Send(1, MsgType.ObjMoveRequest, delegate(BinaryWriter bw) { ObjMoveSync.WriteEntries(bw, changes); }); } }; _population.OnHostSnapshot = delegate(List<List<PopulationSync.Entry>> all) { Broadcast(MsgType.PopState, delegate(BinaryWriter bw) { PopulationSync.Write(bw, all); }); }; _boxes.OnHostSnapshot = delegate(List<BoxSync.Entry> list) { Broadcast(MsgType.BoxState, delegate(BinaryWriter bw) { BoxSync.WriteEntries(bw, list); }); }; _boxes.OnClientChanges = delegate(List<BoxSync.Entry> list) { Send(1, MsgType.BoxRequest, delegate(BinaryWriter bw) { BoxSync.WriteEntries(bw, list); }); }; BoxSync.IsLocallyCarried = delegate(InteractablePackagingBox_Item box) { if ((Object)(object)_playerIpc == (Object)null || (Object)(object)box == (Object)null) { return false; } try { if (_heldBoxFrame != Time.frameCount) { _heldBoxFrame = Time.frameCount; _heldBoxA = FiHoldItemBox?.GetValue(_playerIpc); _heldBoxB = FiHoldBox?.GetValue(_playerIpc); _heldBoxC = FiHoldBoxCard?.GetValue(_playerIpc); } return _heldBoxA == box || _heldBoxB == box; } catch { return false; } }; CardBoxSync.IsLocallyCarried = delegate(InteractablePackagingBox_Card box) { if ((Object)(object)_playerIpc == (Object)null || (Object)(object)box == (Object)null) { return false; } try { if (_heldBoxFrame != Time.frameCount) { _heldBoxFrame = Time.frameCount; _heldBoxA = FiHoldItemBox?.GetValue(_playerIpc); _heldBoxB = FiHoldBox?.GetValue(_playerIpc); _heldBoxC = FiHoldBoxCard?.GetValue(_playerIpc); } return _heldBoxC == box || _heldBoxB == box; } catch { return false; } }; BoxSync.LocalBoxDestroyed = delegate(InteractablePackagingBox_Item box) { if (InGameLevel() && !ClientReloading) { if (Role == CoopRole.Client) { _boxes.NotifyLocalDestroyed(box); } else if (Role == CoopRole.Host) { _boxes.HostNotifyLocalDestroyed(); } } }; _boxes.OnLocalRemoved = delegate(int idx, int type) { Send(1, MsgType.BoxRemoved, delegate(BinaryWriter bw) { bw.Write(idx); Msg.WriteItemType(bw, (EItemType)type); }); }; PopulationSync.OnClientStructureChanged = delegate(int kind) { if (Role == CoopRole.Client && (kind == 2 || kind == 3)) { _cardShelves.InvalidateBaseline(); } }; _actCardPriceRetry = CardPriceRetryTick; _actFrameCardWork = FlushFrameCardWork; _actNetPump = delegate { _net.PumpMainThread(); }; _actAvatars = delegate { AvatarManager.ViewCamera = _playerCamTf; _avatars.Tick(_dt); }; _actWorld = delegate { _world.Tick(_dt, _syncActive); }; _actCardShelves = delegate { _cardShelves.IsClientRole = Role == CoopRole.Client; _cardShelves.Tick(_dt, _syncActive); }; _actObjMoves = delegate { _objMoves.Tick(_dt, _syncActive); }; _actBoxes = delegate { if (Role == CoopRole.Host) { _boxes.HostTick(_dt, _syncActive); } else if (Role == CoopRole.Client) { _boxes.ClientTick(_dt, _syncActive && !ClientPreloadHold); } }; _actPopulation = delegate { if (Role == CoopRole.Host) { _population.HostTick(_dt, _syncActive); } }; _actNpcPuppets = delegate { _npcs.TickPuppets(_dt, InGameLevel()); }; _actRegisterMirror = RegisterMirrorTick; _actNpcSweep = NpcSweepTick; _actStateSend = StateSendTick; _actNpcCollect = NpcCollectTick; _actRegisterCollect = RegisterCollectTick; _grading.SendOp = delegate(Action<BinaryWriter> w) { Send(1, MsgType.GradingOp, w); }; _grading.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.GradingState, w); }; _trades.SendOp = delegate(Action<BinaryWriter> w) { Send(1, MsgType.TradeOp, w); }; _trades.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.TradeState, w); }; _tables.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.TableState, w); }; _staff.SendOp = delegate(Action<BinaryWriter> w) { Send(1, MsgType.StaffOp, w); }; _staff.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.StaffState, w); }; _shopState.SendOp = delegate(Action<BinaryWriter> w) { Send(1, MsgType.ShopOp, w); }; _shopState.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.ShopState, w); }; _settings.SendOp = delegate(Action<BinaryWriter> w) { Send(1, MsgType.SettingsOp, w); }; _settings.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.SettingsState, w); }; _market.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.MarketState, w); }; _report.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.ReportState, w); }; _containers.SendOp = delegate(Action<BinaryWriter> w) { Send(1, MsgType.ContainerOp, w); }; _containers.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.ContainerState, w); }; _containers.RequestBoxResync = delegate { _boxes.ForceBroadcastNextTick(); }; _tournament.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.TournamentState, w); }; _cardBoxes.SendOp = delegate(Action<BinaryWriter> w) { Send(1, MsgType.CardBoxOp, w); }; _cardBoxes.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.CardBoxState, w); }; _furnBoxes.SendOp = delegate(Action<BinaryWriter> w) { Send(1, MsgType.FurnBoxOp, w); }; _furnBoxes.BroadcastState = delegate(Action<BinaryWriter> w) { Broadcast(MsgType.FurnBoxState, w); }; FurnBoxSync.IsLocallyCarried = delegate(InteractablePackagingBox_Shelf box) { if ((Object)(object)_playerIpc == (Object)null || (Object)(object)box == (Object)null) { return false; } try { if (_heldBoxFrame != Time.frameCount) { _heldBoxFrame = Time.frameCount; _heldBoxA = FiHoldItemBox?.GetValue(_playerIpc); _heldBoxB = FiHoldBox?.GetValue(_playerIpc); _heldBoxC = FiHoldBoxCard?.GetValue(_playerIpc); } return _heldBoxB == box; } catch { return false; } }; _actModules = ModulesTick; SceneManager.sceneLoaded += OnSceneLoaded; string[] commandLineArgs = Environment.GetCommandLineArgs(); for (int num = 0; num < commandLineArgs.Length; num++) { string text = commandLineArgs[num]; ulong result2; if (text.StartsWith("-coopautohost=") && int.TryParse(text.Substring(14), out var result)) { _autoHostSlot = result; } else if (text.StartsWith("-coopautojoin=")) { _autoJoinIp = text.Substring(14); } else if (text == "+connect_lobby" && num + 1 < commandLineArgs.Length && ulong.TryParse(commandLineArgs[num + 1], out result2)) { _autoJoinSteamLobby = result2; } } if (_autoHostSlot >= 0) { CoopPlugin.Log.LogInfo((object)$"AUTO: will load slot {_autoHostSlot} and host"); } if (_autoJoinIp != null) { CoopPlugin.Log.LogInfo((object)("AUTO: will join " + _autoJoinIp)); } if (_autoJoinSteamLobby != 0L) { CoopPlugin.Log.LogInfo((object)$"AUTO: will join Steam lobby {_autoJoinSteamLobby}"); } _steamLobby.Init(); _steamLobby.OnError = delegate(string err) { ErrorLine = err; CoopPlugin.Log.LogWarning((object)err); }; _steamLobby.OnLobbyCreated = delegate(CSteamID lobby) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) if (_net is SteamTransport steamTransport) { steamTransport.LobbyId = lobby; } StatusLine = "Hosting via Steam - click 'Invite friend'"; ManualLogSource log = CoopPlugin.Log; CSteamID val = lobby; log.LogInfo((object)("steam: lobby live " + ((object)(*(CSteamID*)(&val))/*cast due to .constrained prefix*/).ToString())); }; _steamLobby.OnEnteredLobby = delegate(CSteamID owner) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (Role == CoopRole.Client && _net is SteamTransport steamTransport) { steamTransport.LobbyId = _steamLobby.LobbyId; steamTransport.ConnectToHost(owner); StatusLine = "Connected via Steam - requesting world..."; SendHello(); } }; _steamLobby.OnInviteAccepted = delegate(CSteamID lobby) { //IL_000a: 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_0024: Unknown result type (might be due to invalid IL or missing references) ManualLogSource log = CoopPlugin.Log; CSteamID val = lobby; log.LogInfo((object)("steam: invite accepted -> lobby " + ((object)(*(CSteamID*)(&val))/*cast due to .constrained prefix*/).ToString())); JoinSteam(lobby); }; CEventManager.AddListener<CEventPlayer_OnOpenCardPack>((EventDelegate<CEventPlayer_OnOpenCardPack>)OnLocalPackOpened); try { EnumLendState(); } catch { } } public static string EnumLendState() { try { if (!ModParity.HostEnumInstalled()) { return null; } if (!_enumLendWarned) { _enumLendWarned = true; CoopPlugin.Log.LogWarning((object)"CardShopCoop: your custom-card database is currently the HOST's synced copy from a co-op session. Your OWN solo modded saves may not load until you restore it (restore via the co-op window) and RESTART the game."); } return "custom-card database is the HOST's copy (co-op sync) - solo modded saves may not load; restore via the co-op window"; } catch { return null; } } public void JoinSteam(CSteamID lobby, string password = "") { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) ErrorLine = ""; if (Role != CoopRole.None) { ErrorLine = "Already in a session."; return; } if (InGameLevel()) { ErrorLine = "Go to the main menu first, then accept the invite again."; return; } if (!_steamLobby.SteamAvailable()) { ErrorLine = "Steam isn't running."; return; } if (ModParity.RestartRequiredForJoin) { ErrorLine = "the host's card database was installed on this PC - RESTART the game before joining"; return; } Role = CoopRole.Client; GuestBorrowedWorld = true; IsSteamSession = true; _joinPassword = password ?? ""; LastFailedLobby = lobby; _net = new SteamTransport(isHost: false) { KeepaliveFrame = Msg.Build(MsgType.Ping) }; StatusLine = "Joining Steam lobby..."; _steamLobby.Join(lobby); } public void StartHostingSteam(bool isPublic, string lobbyName, string password) { ErrorLine = ""; if (Role != CoopRole.None) { ErrorLine = "Already in a session."; return; } if (!InGameLevel()) { ErrorLine = "Load your shop first, then host."; return; } if (!_steamLobby.SteamAvailable()) { ErrorLine = "Steam isn't running - use LAN instead."; return; } CardShopCoop.Util.EnumMap.Clear(); Role = CoopRole.Host; IsSteamSession = true; HostPassword = password ?? ""; _net = new SteamTransport(isHost: true) { KeepaliveFrame = Msg.Build(MsgType.Ping) }; StatusLine = "Creating Steam lobby..."; _steamLobby.Host(isPublic, lobbyName, HostPassword.Length > 0); } public void OpenSteamInvite() { _steamLobby.OpenInviteDialog(); } private void SendHello() { Send(1, MsgType.Hello, delegate(BinaryWriter bw) { bw.Write("1.0.37"); bw.Write(CoopPlugin.PlayerName.Value); bw.Write(_joinPassword ?? ""); bw.Write(ModParity.PluginHash()); bw.Write(ModParity.EnumHash()); bw.Write(ModParity.CardsHash()); WriteCappedList(bw, ModParity.PluginList()); WriteCappedList(bw, ModParity.CardsList()); byte[] array; try { array = Msg.Gzip(Encoding.UTF8.GetBytes(string.Join("\n", ModParity.EnumLines()))); } catch (Exception ex) { CoopPlugin.Log.LogWarning((object)("enum lines for Hello: " + ex.Message)); array = Msg.Gzip(new byte[0]); } bw.Write(array.Length); bw.Write(array); }); } private static List<string> SafeEnumLines() { try { return ModParity.EnumLines() ?? new List<string>(); } catch (Exception ex) { CoopPlugin.Log.LogWarning((object)("enum lines: " + ex.Message)); return new List<string>(); } } private static List<string> SafeCardsList() { try { return ModParity.CardsList() ?? new List<string>(); } catch (Exception ex) { CoopPlugin.Log.LogWarning((object)("cards list: " + ex.Message)); return new List<string>(); } } private static byte[] GzipLines(List<string> lines) { try { string[] array = (lines ?? new List<string>()).ToArray(); byte[] bytes = Encoding.UTF8.GetBytes(string.Join("\n", array)); if (bytes.Length > 262144) { CoopPlugin.Log.LogWarning((object)("registry blob is OVER THE WIRE CAP: " + array.Length + " ids, " + bytes.Length + " bytes uncompressed vs a " + 262144 + "-byte cap - the other PC will IGNORE it and modded ids will not be translated this session (ids must already match)")); } return Msg.Gzip(bytes); } catch (Exception ex) { CoopPlugin.Log.LogWarning((object)("registry blob: " + ex.Message)); return Msg.Gzip(new byte[0]); } } private static List<string> ReadCappedEnumBlob(BinaryReader br, out string digest) { digest = "none"; List<string> list = new List<string>(); try { int num = br.ReadInt32(); if (num <= 0) { return list; } if (num > 262144) { int num2 = num; while (num2 > 0) { int num3 = br.ReadBytes(Math.Min(num2, 8192)).Length; if (num3 <= 0) { break; } num2 -= num3; } CoopPlugin.Log.LogWarning((object)("registry blob over cap (" + num + " bytes compressed, cap " + 262144 + ") - ignored; modded ids will not be translated from it")); return list; } byte[] array = br.ReadBytes(num); if (array.Length != num) { return list; } string text = GunzipCapped(array, 262144); if (text == null) { return list; } digest = Fnv(text).ToString("X8"); string[] array2 = text.Split(new char[1] { '\n' }); for (int i = 0; i < array2.Length; i++) { string text2 = array2[i].Trim(); if (text2.Length > 0) { list.Add(text2); } } } catch { } return list; } private static string GunzipCapped(byte[] data, int cap) { try { using MemoryStream stream = new MemoryStream(data, writable: false); using GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress); using MemoryStream memoryStream = new MemoryStream(); byte[] array = new byte[8192]; int num; while ((num = gZipStream.Read(array, 0, array.Length)) > 0) { if (memoryStream.Length + num > cap) { CoopPlugin.Log.LogWarning((object)("registry blob unpacked OVER CAP (more than " + cap + " bytes from " + data.Length + " compressed) - ignored, NOT a vanilla peer")); return null; } memoryStream.Write(array, 0, num); } return Encoding.UTF8.GetString(memoryStream.ToArray()); } catch (Exception ex) { CoopPlugin.Log.LogWarning((object)("registry blob could not be unpacked (" + data.Length + " bytes, not valid gzip: " + ex.Message + ") - ignored")); return null; } } private static List<string> EnumConflicts(List<string> theirs, List<string> ours) { List<string> list = new List<string>(); if (theirs == null || theirs.Count == 0 || ours == null || ours.Count == 0) { return list; } Dictionary<string, string> dictionary = EnumMap(theirs); Dictionary<string, string> dictionary2 = EnumMap(ours); foreach (KeyValuePair<string, string> item in dictionary) { if (dictionary2.TryGetValue(item.Key, out var value) && value != item.Value) { list.Add(item.Key + " -> yours " + item.Value + ", host " + value); } } list.Sort(StringComparer.Ordinal); return list; } private static Dictionary<string, string> EnumMap(List<string> lines) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (string line in lines) { if (!string.IsNullOrEmpty(line)) { int num = line.LastIndexOf('='); if (num > 0 && num != line.Length - 1) { dictionary[line.Substring(0, num)] = line.Substring(num + 1); } } } return dictionary; } private static string DescribeConflicts(List<string> conflicts) { int num = Math.Min(conflicts.Count, 5); string text = string.Join("; ", conflicts.GetRange(0, num).ToArray()); if (conflicts.Count > num) { text += $" (+{conflicts.Count - num} more)"; } if (text.Length > 400) { text = text.Substring(0, 397) + "..."; } return text; } private static string PeerSyncKey(string name, string enumDigest) { string text = (name ?? "").Trim().ToLowerInvariant(); string text2 = (string.IsNullOrEmpty(enumDigest) ? "none" : enumDigest); return ((text.Length > 0) ? ("n:" + text) : "anon") + "|" + text2; } private static void WriteCappedList(BinaryWriter bw, List<string> list) { int num = ((list != null) ? Math.Min(list.Count, 256) : 0); bw.Write(num); for (int i = 0; i < num; i++) { bw.Write(list[i] ?? ""); } } private static List<string> ReadCappedList(BinaryReader br) { List<string> list = new List<string>(); try { int num = br.ReadInt32(); if (num < 0) { num = 0; } if (num > 256) { num = 256; } for (int i = 0; i < num; i++) { list.Add(br.ReadString()); } } catch { } return list; } private static string DescribeModDiff(List<string> theirs, List<string> ours, string head, string diffLabel) { if (theirs == null || theirs.Count == 0 || ours == null || ours.Count == 0) { return null; } Dictionary<string, string> dictionary = DiffMap(theirs); Dictionary<string, string> dictionary2 = DiffMap(ours); List<string> list = new List<string>(); List<string> list2 = new List<string>(); List<string> list3 = new List<string>(); foreach (KeyValuePair<string, string> item in dictionary2) { if (!dictionary.ContainsKey(item.Key)) { list.Add(item.Key); } } foreach (KeyValuePair<string, string> item2 in dictionary) { if (!dictionary2.TryGetValue(item2.Key, out var value)) { list2.Add(item2.Key); } else if (value != item2.Value) { list3.Add(item2.Key + " (host " + value + " vs yours " + item2.Value + ")"); } } if (list.Count == 0 && list2.Count == 0 && list3.Count == 0) { return null; } list.Sort(StringComparer.Ordinal); list2.Sort(StringComparer.Ordinal); list3.Sort(StringComparer.Ordinal); List<string> list4 = new List<string>(); if (list.Count > 0) { list4.Add("you are missing: " + JoinCapped(list)); } if (list2.Count > 0) { list4.Add("you have extra: " + JoinCapped(list2)); } if (list3.Count > 0) { list4.Add(diffLabel + ": " + JoinCapped(list3)); } string text = head + string.Join(" | ", list4); if (text.Length > 700) { text = text.Substring(0, 697) + "..."; } return text; } private static Dictionary<string, string> DiffMap(List<string> entries) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (string entry in entries) { if (!string.IsNullOrEmpty(entry)) { int num = entry.IndexOf('='); string key = ((num > 0) ? entry.Substring(0, num) : entry); string value = ((num > 0) ? entry.Substring(num + 1) : ""); dictionary[key] = value; } } return dictionary; } private static string JoinCapped(List<string> items) { StringBuilder stringBuilder = new StringBuilder(); int num = 0; for (int i = 0; i < items.Count; i++) { string text = ((num > 0) ? ", " : "") + items[i]; if (num > 0 && stringBuilder.Length + text.Length > 220) { break; } stringBuilder.Append(text); num++; } if (num < items.Count) { stringBuilder.Append($" (+{items.Count - num} more)"); } return stringBuilder.ToString(); } private void RejectConn(int connId, string reason) { CoopPlugin.Log.LogWarning((object)$"rejected connection {connId}: {reason}"); Send(connId, MsgType.Bye, delegate(BinaryWriter bw) { bw.Write(reason); }); _pendingKicks.Add(new KeyValuePair<int, float>(connId, 1.5f)); } private static void ReadHoldPayload(BinaryReader br, byte hold, out List<int> types, out List<CardData> cards) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected I4, but got Unknown types = null; cards = null; int num = br.ReadByte(); if (num == 0) { return; } if (hold == 3) { cards = new List<CardData>(num); for (int i = 0; i < num; i++) { cards.Add(Msg.ReadCard(br)); } } else { types = new List<int>(num); for (int j = 0; j < num; j++) { types.Add((int)Msg.ReadItemType(br)); } } } private static void WriteHoldPayload(BinaryWriter bw, byte hold, List<int> types, List<CardData> cards) { if (hold == 3) { bw.Write((byte)(cards?.Count ?? 0)); if (cards == null) { return; } { foreach (CardData card in cards) { Msg.WriteCard(bw, card); } return; } } bw.Write((byte)(types?.Count ?? 0)); if (types == null) { return; } foreach (int type in types) { Msg.WriteItemType(bw, (EItemType)type); } } private static bool ApplyCardDelta(bool isAdd, int amount, CardData card, out bool relayAnyway) { relayAnyway = false; if (card.cardGrade != 0 && (card.cardGrade < 1 || card.cardGrade > 10) && !GradingInterop.Present) { CoopPlugin.Log.LogWarning((object)$"card delta: dropping corrupt graded card {CardIdent(card)} (grade {card.cardGrade}) - not applied (Grading Overhaul absent)"); return false; } GamePatches.ApplyingRemoteCards = true; try { if (!CardSetInstalledHere(card)) { relayAnyway = true; if (_priceWarnedKeys.Add("delta:" + CardPriceKey(card))) { CoopPlugin.Log.LogWarning((object)("card delta: " + CardIdent(card) + " is from a card set you don't have installed - skipped")); } return false; } if (isAdd) { if (card.cardGrade > 10) { GradingInterop.Remember(card); } CPlayerData.AddCard(card, amount); } else if (card.cardGrade > 0) { int num = 0; for (int i = 0; i < amount; i++) { if (!CPlayerData.HasGradedCardInAlbum(card)) { break; } CPlayerData.RemoveGradedCard(card, true); num++; } if (num == 0) { CoopPlugin.Log.LogWarning((object)$"graded remove: {CardIdent(card)} (grade {card.cardGrade}) not in this album - skipped (album mismatch?)"); return false; } } else { int cardAmount = CPlayerData.GetCardAmount(card); if (cardAmount < amount) { CoopPlugin.Log.LogWarning((object)$"card delta would drive {CardIdent(card)} negative (have {cardAmount}, remove {amount}) - skipped (card registry mismatch?)"); return false; } CPlayerData.ReduceCard(card, amount); } } finally { GamePatches.ApplyingRemoteCards = false; } _deltaAppliedThisFrame++; if (_deltaLogBuf.Count < 5) { _deltaLogBuf.Add(new PendingCard { IsAdd = isAdd, Amount = amount, Card = SnapshotCard(card) }); } _binderRefreshPending = true; return true; } private static void ReadCardDelta(BinaryReader br, out bool isAdd, out int amount, out CardData card) { isAdd = br.ReadBoolean(); amount = br.ReadInt32(); card = Msg.ReadCard(br); } private bool ApplyOrHoldCardDelta(bool isAdd, int amount, CardData card, out bool relayAnyway) { relayAnyway = false; if (!InGameLevel()) { _pendingCardDeltas.Add(new PendingCard { IsAdd = isAdd, Amount = amount, Card = card }); return false; } return ApplyCardDelta(isAdd, amount, card, out relayAnyway); } private static CardData SnapshotCard(CardData c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown return new CardData { expansionType = c.expansionType, monsterType = c.monsterType, borderType = c.borderType, isFoil = c.isFoil, isDestiny = c.isDestiny, isChampionCard = c.isChampionCard, isNew = c.isNew, cardGrade = c.cardGrade, gradedCardIndex = c.gradedCardIndex }; } private static string CardPriceKey(CardData card) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected I4, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected I4, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected I4, but got Unknown if (card == null) { return null; } return (int)card.expansionType + ":" + (int)card.monsterType + ":" + (int)card.borderType + ":" + (card.isFoil ? 1 : 0) + (card.isDestiny ? 1 : 0) + (card.isChampionCard ? 1 : 0) + ":" + card.cardGrade; } internal static void ClearCardSetCache() { _shownMonsters.Clear(); } private static bool MonsterHasDataRowHere(ECardExpansionType expansion, EMonsterType monster) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Inv() == (Object)null) { return false; } if (!_shownMonsters.TryGetValue(expansion, out var value)) { List<EMonsterType> shownMonsterList = InventoryBase.GetShownMonsterList(expansion); if (shownMonsterList == null || shownMonsterList.Count == 0) { return false; } value = new HashSet<EMonsterType>(shownMonsterList); _shownMonsters[expansion] = value; } return value.Contains(monster); } internal static bool CardSetInstalledHere(CardData card) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_001b: 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) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) try { if (card == null) { return false; } if ((int)card.expansionType == -1) { return false; } if ((int)card.monsterType == 0) { return false; } if (!Enum.IsDefined(typeof(ECardExpansionType), card.expansionType)) { return false; } if (CPlayerData.GetCardCollectedList(card.expansionType, card.isDestiny) == null) { return false; } return MonsterHasDataRowHere(card.expansionType, card.monsterType); } catch (Exception ex) { if (_priceWarnedKeys.Add("check:" + CardPriceKey(card))) { CoopPlugin.Log.LogWarning((object)("card set check: " + ex.Message)); } return false; } } private static string CardIdent(CardData c) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected I4, but got Unknown if (c == null) { return "(null card)"; } if ((int)c.expansionType < 7) { return ((object)Unsafe.As<EMonsterType, EMonsterType>(ref c.monsterType)/*cast due to .constrained prefix*/).ToString(); } return ((object)Unsafe.As<ECardExpansionType, ECardExpansionType>(ref c.expansionType)/*cast due to .constrained prefix*/).ToString() + "#" + (int)c.monsterType; } internal static void WarnRefusedCard(CardData c, string context) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected I4, but got Unknown if (c != null && _priceWarnedKeys.Add(context + ":" + CardPriceKey(c))) { CoopPlugin.Log.LogWarning((object)$"{context}: {c.expansionType}#{(int)c.monsterType} is from a card set this PC doesn't have - the card could NOT be processed here"); } } private static bool ApplyRemoteCardPrice(CardData card, float price, string from, out float actual, out bool relayAnyway) { actual = price; relayAnyway = false; if (card == null) { return false; } string text = CardPriceKey(card); if (!CardSetInstalledHere(card)) { relayAnyway = true; if (_priceWarnedKeys.Add("set:" + text)) { CoopPlugin.Log.LogWarning((object)("card price for unknown card set skipped - other side has a content pack this PC doesn't (" + text + "; further ones logged once each)")); } return false; } if (card.cardGrade > 10) { if (!GradingInterop.Present) { relayAnyway = true; return false; } GradingInterop.Remember(card); } float num = float.NaN; try { num = CPlayerData.GetCardPrice(card); } catch { } try { CPlayerData.SetCardPrice(card, price); } catch (Exception ex) { CoopPlugin.Log.LogWarning((object)("card price apply: " + ex.Message)); return false; } try { actual = CPlayerData.GetCardPrice(card); } catch (Exception ex2) { if (_priceWarnedKeys.Add("read:" + text)) { CoopPlugin.Log.LogWarning((object)("card price read-back: " + ex2.Message)); } actual = price; } if (Math.Abs(actual - price) > 0.0075f) { if (_priceWarnedKeys.Add("store:" + text)) { CoopPlugin.Log.LogWarning((object)$"card price {text}: the game's price store did not accept {price:F4} (it holds {actual:F4}) - modded expansion? (logged once per card)"); } relayAnyway = true; return false; } if (float.IsNaN(num) || Math.Abs(num - actual) > 0.0075f) { CoopPlugin.Log.LogInfo((object)$"card price applied: {text} = {actual:F2} (from {from})"); } return true; } private static void RefreshOpenBinder() { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Invalid comparison between Unknown and I4 //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_deltaIpc == (Object)null) { _deltaIpc = Object.FindObjectOfType<InteractionPlayerController>(); } CollectionBinderFlipAnimCtrl val = (((Object)(object)_deltaIpc != (Object)null) ? _deltaIpc.m_CollectionBinderFlipAnimCtrl : null); if ((Object)(object)val == (Object)null) { return; } val.SetCanUpdateSort(true); bool flag = FiBinderIsBookOpen != null && (bool)FiBinderIsBookOpen.GetValue(val); if (flag && MiBinderResort != null) { MiBinderResort.Invoke(val, new object[1] { false }); } if (!flag || !(FiBinderUI != null)) { return; } object? value = FiBinderUI.GetValue(val); CollectionBinderUI val2 = (CollectionBinderUI)((value is CollectionBinderUI) ? value : null); if (!((Object)(object)val2 != (Object)null)) { return; } bool num = FiBinderIsGradedAlbum != null && (bool)FiBinderIsGradedAlbum.GetValue(val); ECardExpansionType val3 = (ECardExpansionType)((!(FiBinderExpansionType != null)) ? (-1) : ((int)(ECardExpansionType)FiBinderExpansionType.GetValue(val))); if (num) { float num2 = 0f; for (int i = 0; i < CPlayerData.m_GradedCardInventoryList.Count; i++) { if (CPlayerData.m_GradedCardInventoryList[i].amount > 10) { CPlayerData.m_GradedCardInventoryList[i].amount = 10; } num2 += CPlayerData.GetCardMarketPrice(CPlayerData.GetGradedCardData(CPlayerData.m_GradedCardInventoryList[i])); } val2.SetTotalValue(num2); } else if ((int)val3 == 2) { val2.SetTotalValue(CPlayerData.GetCardAlbumTotalValue(val3, false) + CPlayerData.GetCardAlbumTotalValue(val3, true)); } else { val2.SetTotalValue(CPlayerData.GetCardAlbumTotalValue(val3, false)); } } catch (Exception ex) { CoopPlugin.Log.LogWarning((object)("binder relayout after card change failed: " + ex.Message)); } } private void FlushPendingCardWork() { if (!InGameLevel() || (_pendingCardDeltas.Count == 0 && _pendingCardPrices.Count == 0)) { return; } Guarded("pending-cards", delegate { foreach (PendingCard pendingCardDelta in _pendingCardDeltas) { ApplyCardDelta(pendingCardDelta.IsAdd, pendingCardDelta.Amount, pendingCardDelta.Card, out var _); } if (_pendingCardDeltas.Count > 0) { CoopPlugin.Log.LogInfo((object)$"applied {_pendingCardDeltas.Count} card change(s) held during loading"); } _pendingCardDeltas.Clear(); bool flag = Role == CoopRole.Host; List<KeyValuePair<CardData, float>> list = (flag ? new List<KeyValuePair<CardData, float>>() : null); GamePatches.ApplyingRemotePrice = true; try { foreach (KeyValuePair<CardData, float> pendingCardPrice in _pendingCardPrices) { float actual; bool relayAnyway2; bool flag2 = ApplyRemoteCardPrice(pendingCardPrice.Key, pendingCardPrice.Value, "load queue", out actual, out relayAnyway2); if (flag) { if (flag2) { list.Add(new KeyValuePair<CardData, float>(pendingCardPrice.Key, actual)); } else if (relayAnyway2) { list.Add(pendingCardPrice); } } } } catch (Exception ex) { CoopPlugin.Log.LogWarning((object)("pending card price apply: " + ex.Message)); } finally { GamePatches.ApplyingRemotePrice = false; } _pendingCardPrices.Clear(); if (list != null) { for (int i = 0; i < list.Count; i++) { KeyValuePair<CardData, float> kv = list[i]; Broadcast(MsgType.CardPriceSet, delegate(BinaryWriter bw) { Msg.WriteCard(bw, kv.Key); bw.Write(kv.Value); }); } } }); } private void RelayRawToOthers(int senderConn, MsgType type, byte[] payload) { if (Role != CoopRole.Host || _net == null || _net.ConnectionCount <= 1) { return; } FlushCardDeltaOutbox(); byte[] frame = Msg.Build(type, delegate(BinaryWriter bw) { if (payload != null) { bw.Write(payload); } }); foreach (int item in _net.ConnIds()) { if (item != senderConn) { _net.Send(item, frame); } } } private void RelayCardDeltaBatchToOthers(int senderConn, List<PendingCard> deltas) { if (Role != CoopRole.Host || _net == null || _net.ConnectionCount <= 1 || deltas.Count == 0) { return; } FlushCardDeltaOutbox(); byte[] frame = Msg.Build(MsgType.CardDeltaBatch, delegate(BinaryWriter bw) { bw.Write(deltas.Count); for (int i = 0; i < deltas.Count; i++) { bw.Write(deltas[i].IsAdd); bw.Write(deltas[i].Amount); Msg.WriteCard(bw, deltas[i].Card); } }); foreach (int item in _net.ConnIds()) { if (item != senderConn) { _net.Send(item, frame); } } } private void FlushCardDeltaOutbox() { if (_cardDeltaOutbox.Count == 0 || _flushingCardDeltas) { return; } if (_net == null) { _cardDeltaOutbox.Clear(); return; } _flushingCardDeltas = true; try { int count = _cardDeltaOutbox.Count; int n; for (int i = 0; i < count; i += n) { int start = i; n = Math.Min(200, count - start); Broadcast(MsgType.CardDeltaBatch, delegate(BinaryWriter bw) { bw.Write(n); for (int j = start; j < start + n; j++) { PendingCard pendingCard = _cardDeltaOutbox[j]; bw.Write(pendingCard.IsAdd); bw.Write(pendingCard.Amount); Msg.WriteCard(bw, pendingCard.Card); } }); } if (count > 200) { CoopPlugin.Log.LogInfo((object)$"card deltas: {count} sent as {(count + 200 - 1) / 200} batch(es)"); } _cardDeltaOutbox.Clear(); } finally { _flushingCardDeltas = false; } } private void FlushFrameCardWork() { if (_deltaAppliedThisFrame > 0) { if (_deltaAppliedThisFrame <= 5) { for (int i = 0; i < _deltaLogBuf.Count; i++) { PendingCard pendingCard = _deltaLogBuf[i]; CoopPlugin.Log.LogInfo((object)string.Format("card delta applied: {0}{1} {2}{3}", pendingCard.IsAdd ? "+" : "-", pendingCard.Amount, CardIdent(pendingCard.Card), (pendingCard.Card.cardGrade > 0) ? $" (grade {pendingCard.Card.cardGrade})" : (pendingCard.Card.isFoil ? " (foil)" : ""))); } } else { CoopPlugin.Log.LogInfo((object)$"applied {_deltaAppliedThisFrame} card deltas"); } _deltaLogBuf.Clear(); _deltaAppliedThisFrame = 0; } if (_binderRefreshPending) { _binderRefreshPending = false; RefreshOpenBinder(); } FlushCardDeltaOutbox(); } private void RelayTagToOthers(int senderConn, byte kind, int extra = -1) { if (Role != CoopRole.Host || _net == null || _net.ConnectionCount <= 1) { return; } byte[] frame = Msg.Build(MsgType.RelayTag, delegate(BinaryWriter bw) { bw.Write((byte)senderConn); bw.Write(kind); Msg.WriteItemType(bw, (EItemType)extra); }); foreach (int item in _net.ConnIds()) { if (item != senderConn) { _net.Send(item, frame); } } } private void BroadcastRoster() { if (Role != CoopRole.Host) { return; } List<KeyValuePair<int, string>> entries = new List<KeyValuePair<int, string>>(PeerNames); Broadcast(MsgType.Roster, delegate(BinaryWriter bw) { bw.Write((byte)entries.Count); foreach (KeyValuePair<int, string> item in entries) { bw.Write((byte)item.Key); bw.Write(item.Value); } }); } private void OnLocalPackOpened(CEventPlayer_OnOpenCardPack evt) { if (Role != CoopRole.None && _net != null && _net.ConnectionCount > 0) { Broadcast(MsgType.Activity, delegate(BinaryWriter bw) { bw.Write((byte)1); Msg.WriteItemType(bw, (EItemType)evt.m_PackIndex); }); } } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; CEventManager.RemoveListener<CEventPlayer_OnOpenCardPack>((EventDelegate<CEventPlayer_OnOpenCardPack>)OnLocalPackOpened); Shutdown("plugin unloaded"); } private void OnApplicationQuit() { Shutdown("game closed"); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { _avatars.Clear(); _world.Reset(); _npcs.Reset(); _cardShelves.Reset(); _objMoves.Reset(); _boxes.Reset(); _population.Reset(); _registerMirror.Reset(); ModulesReset(); PromptLine = ""; _lightManager = null; _cmSweep = null; _cmSpray = null; _inventory = null; _renamerHandled = false; _catalogSent = false; if (ClientReloading) { _reloadGrace = 10f; } _playerTf = null; _playerCamTf = null; _playerIpc = null; if (((Scene)(ref scene)).name == "Title" && Role == CoopRole.Client && _net != null) { Shutdown("left the session"); } else if (((Scene)(ref scene)).name != "Title" && Role != CoopRole.None && _net != null && !ClientReloading) { Shutdown("left the session (world reloaded)"); } } private bool InGameLevel() { CGameManager instance = CSingleton<CGameManager>.Instance; if ((Object)(object)instance != (Object)null) { return instance.m_IsGameLevel; } return false; } private static InventoryBase Inv() { if ((Object)(object)_inventory == (Object)null) { _inventory = Object.FindObjectOfType<InventoryBase>(); } return _inventory; } private void ModulesTick() { bool flag = InGameLevel(); if (Role == CoopRole.Host) { _grading.HostTick(_dt, flag); _trades.HostTick(_dt, flag); _tables.HostTick(_dt, flag); _staff.HostTick(_dt, flag); _shopState.HostTick(_dt, flag); _settings.HostTick(_dt, flag); _market.HostTick(_dt, flag); _report.HostTick(_dt, flag); _containers.HostTick(_dt, flag); _tournament.HostTick(_dt, flag); _cardBoxes.HostTick(_dt, flag); _furnBoxes.HostTick(_dt, flag); } else { if (Role != CoopRole.Client) { return; } _trades.ClientTick(_dt, flag); _cardBoxes.ClientTick(_dt, flag && !ClientPreloadHold); _furnBoxes.ClientTick(_dt, flag && !ClientPreloadHold); _catalogTimer += _dt; if (flag && (_catalogTimer >= 45f || !_catalogSent)) { _catalogTimer = 0f; _catalogSent = true; int num = LocalCatalogHash(); if (num != _lastCatalogSentHash) { _lastCatalogSentHash = num; SendCatalogDigest(); } } } } private static int LocalCatalogHash() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected I4, but got Unknown try { int num = CatalogCount(); int num2 = 17; for (int i = 0; i < num; i++) { RestockData val = CatalogAt(i); if (val != null) { num2 = num2 * 31 + ((val.itemType << 1) | val.isBigBox); } } return num2; } catch { return 0; } } private void ModulesReset() { _grading.Reset(); _trades.Reset(); _tables.Reset(); _staff.Reset(); _shopState.Reset(); _settings.Reset(); _market.Reset(); _report.Reset(); _containers.Reset(); _tournament.Reset(); _cardBoxes.Reset(); _furnBoxes.Reset(); } private void ModulesForceResend() { _grading.ForceResend(); _trades.ForceResend(); _tables.ForceResend(); _staff.ForceResend(); _shopState.ForceResend(); _settings.ForceResend(); _market.ForceResend(); _report.ForceResend(); _containers.ForceResend(); _tournament.ForceResend(); _cardBoxes.ForceResend(); _furnBoxes.ForceResend(); } private void RegisterMirrorTick() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) _registerMirror.Tick(_dt); _regStateTimer += _dt; if (_regStateTimer >= 0.5f && InGameLevel()) { _regStateTimer -= 0.5f; Transform val = ResolvePlayer(); int nearestCounter = (((Object)(object)val != (Object)null) ? RegisterServe.FindNearestCounter(val.position, CoopPlugin.ServeReach.Value, quiet: true) : (-1)); string text = _trades.PromptFor(nearestCounter) ?? _registerMirror.PromptFor(nearestCounter); if (text == null && Role == CoopRole.Client && _trades.AnyKnownOffer()) { text = $"a customer wants to trade - go to the counter and press {CoopPlugin.ServeKey.Value}"; } PromptLine = text ?? ""; } } private void NpcSweepTick() { if (!_renamerHandled) { _renamerHandled = true; ShopRenamer val = Object.FindObjectOfType<ShopRenamer>(); if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf) { try { _shopSign = (TMP_Text)(object)val.m_ShopName; } catch { } ((Component)val).gameObject.SetActive(false); CoopPlugin.Log.LogInfo((object)"disabled shop-renamer trigger (host names the shop)"); if ((Object)(object)_shopSign != (Object)null && !string.IsNullOrEmpty(_lastShopNameApplied)) { try { _shopSign.text = _lastShopNameApplied; } catch { } } } } if ((Object)(object)_cmSweep == (Object)null) { _cmSweep = Object.FindObjectOfType<CustomerManager>(); } if ((Object)(object)_cmSweep != (Object)null) { List<Customer> customerList = _cmSweep.GetCustomerList(); for (int i = 0; i < customerList.Count; i++) { if ((Object)(object)customerList[i] != (Object)null && ((Component)customerList[i]).gameObject.activeSelf) { ((Component)customerList[i]).gameObject.SetActive(false); } } } List<Worker> workerList = WorkerManager.GetWorkerList(); if (workerList == null) { return; } for (int j = 0; j < workerList.Count; j++) { if ((Object)(object)workerList[j] != (Object)null && ((Component)workerList[j]).gameObject.activeSelf) { ((Component)workerList[j]).gameObject.SetActive(false); } } } private void StateSendTick() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) float num = 1f / Mathf.Clamp(CoopPlugin.SendRateHz.Value, 4f, 30f); Transform val = (InGameLevel() ? ResolvePlayer() : null); if (_stateTimer < num || (Object)(object)val == (Object)null) { return; } Vector3 pos = val.position; float speed = 0f; if (_hasLastPos) { Vector3 val2 = pos - _lastPos; val2.y = 0f; speed = Mathf.Clamp(((Vector3)(ref val2)).magnitude / _stateTimer, 0f, 6f); } _lastPos = pos; _hasLastPos = true; float yaw = (((Object)(object)_playerCamTf != (Object)null) ? _playerCamTf.eulerAngles.y : (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform.eulerAngles.y : val.eulerAngles.y)); byte hold = ComputeHoldState(); BroadcastTransient(MsgType.PlayerState, delegate(BinaryWriter bw) { bw.Write(pos.x); bw.Write(pos.y); bw.Write(pos.z); bw.Write(yaw); bw.Write(speed); bw.Write(hold); if (hold == 3) { bw.Write((byte)_holdCardsBuf.Count); { foreach (CardData item in _holdCardsBuf) { Msg.WriteCard(bw, item); } return; } } bw.Write((byte)_holdTypesBuf.Count); foreach (int item2 in _holdTypesBuf) { Msg.WriteItemType(bw, (EItemType)item2); } }); _diagSent++; _stateTimer = 0f; } private void NpcCollectTick() { List<byte[]> list = _npcs.HostCollect(_dt); if (list == null) { return; } for (int i = 0; i < list.Count; i++) { byte[] c = list[i]; BroadcastTransient(MsgType.NpcState, delegate(BinaryWriter bw) { bw.Write(c); }); } } private void RegisterCollectTick() { _regStateTimer += _dt; if (!(_regStateTimer >= 0.5f)) { return; } _regStateTimer -= 0.5f; byte[] batch = RegisterServe.CollectStates(); if (batch != null) { BroadcastTransient(MsgType.RegisterState, delegate(BinaryWriter bw) { bw.Write(batch); }); } } private Transform ResolvePlayer() { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_playerTf != (Object)null) { return _playerTf; } InteractionPlayerController val = InteractionPlayerController.m_Instance; if ((Object)(object)val == (Object)null) { val = Object.FindObjectOfType<InteractionPlayerController>(); } if ((Object)(object)val != (Object)null) { _playerIpc = val; _playerTf = (((Object)(object)val.m_WalkerCtrl != (Object)null) ? ((Component)val.m_WalkerCtrl).transform : ((Component)val).transform); _playerCamTf = (((Object)(object)val.m_Cam != (Object)null) ? ((Component)val.m_Cam).transform : null); CoopPlugin.Log.LogInfo((object)string.Format("Player body resolved: {0} at {1}, cam={2}", ((Object)_playerTf).name, _playerTf.position, ((Object)(object)_playerCamTf != (Object)null) ? ((Object)_playerCamTf).name : "none")); } return _playerTf; } public static void ForceExitHoldBox(Object heldBox) { CoopCore instance = Instance; InteractionPlayerController val = (((Object)(object)instance != (Object)null) ? instance._playerIpc : null); if ((Object)(object)val == (Object)null) { return; } try { object? obj = FiHoldItemBox?.GetValue(val); object obj2 = FiHoldBox?.GetValue(val); object obj3 = FiHoldBoxCard?.GetValue(val); if (obj == heldBox || obj2 == heldBox || obj3 == heldBox) { val.OnExitHoldBoxMode(); CoopPlugin.Log.LogInfo((object)"ForceExitHoldBox: released hold-box mode for a box being retired by reconcile"); } } catch (Exception ex) { CoopPlugin.Log.LogWarning((object)("ForceExitHoldBox: " + ex.Message)); } } private void RecoverStuckHoldBox() { if ((Object)(object)_playerIpc == (Object)null) { return; } try { object obj = FiIsHoldBoxMode?.GetValue(_playerIpc); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0) { object? obj2 = FiHoldBox?.GetValue(_playerIpc); object? obj3 = ((obj2 is Object) ? obj2 : null); object? obj4 = FiHoldItemBox?.GetValue(_playerIpc); Object val = (Object)((obj4 is Object) ? obj4 : null); object? obj5 = FiHoldBoxCard?.GetValue(_playerIpc); Object val2 = (Object)((obj5 is Object) ? obj5 : null); if ((Object)obj3 == (Object)null && val == (Object)null && val2 == (Object)null) { _playerIpc.OnExitHoldBoxMode(); CoopPlugin.Log.LogInfo((object)"RecoverStuckHoldBox: cleared a stranded hold-box lock (no live held box)"); } } } catch { } } private byte ComputeHoldState() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected I4, but got Unknown //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected I4, but got Unknown _holdTypesBuf.Clear(); _holdCardsBuf.Clear(); if ((Object)(object)_playerIpc == (Object)null) { return 0; } try { if (IsAlive(FiHoldBox) || IsAlive(FiHoldItemBox) || IsAlive(FiHoldBoxShelf) || IsAlive(FiHoldBoxCard)) { object? obj = FiHoldItemBox?.GetValue(_playerIpc); InteractablePackagingBox_Item val = (InteractablePackagingBox_Item)((obj is InteractablePackagingBox_Item) ? obj : null); if (val != null && (Object)(object)val != (Object)null) { _holdTypesBuf.Add(val.m_IsBigBox ? 1 : 0); try { _holdTypesBuf.Add((int)val.m_ItemCompartment.GetItemType()); } catch { _holdTypesBuf.Add(0); } } return 1; } if (FiHoldItemList?.GetValue(_playerIpc) is List<Item> { Count: >0 } list) { for (int i = 0; i < list.Count; i++) { if (_holdTypesBuf.Count >= 6) { break; } if ((Object)(object)list[i] != (Object)null) { _holdTypesBuf.Add((int)list[i].GetItemType()); } } return 2; } if (FiHoldCard3dList?.GetValue(_playerIpc) is List<InteractableCard3d> { Count: >0 } list2) { for (int j = 0; j < list2.Count; j++) { if (_holdCardsBuf.Count >= 4) { break; } InteractableCard3d val2 = list2[j]; if ((Object)(object)val2 != (Object)null && (Object)(object)val2.m_Card3dUI != (Object)null && (Object)(object)val2.m_Card3dUI.m_CardUI != (Object)null) { _holdCardsBuf.Add(val2.m_Card3dUI.m_CardUI.GetCardData()); } } if (_holdCardsBuf.Count > 0) { return 3; } } object obj3 = FiViewAlbum?.GetValue(_playerIpc); bool flag = default(bool); int num; if (obj3 is bool) { flag = (bool)obj3; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0) { return 4; } } catch { } return 0; } private bool IsAlive(FieldInfo fi) { object? obj = fi?.GetValue(_playerIpc); return (Object)((obj is Object) ? obj : null) != (Object)null; } public void StartHosting() { ErrorLine = ""; if (Role != CoopRole.None) { ErrorLine = "Already in a session."; return; } if (!InGameLevel()) { ErrorLine = "Load your shop first, then host."; return; } CardShopCoop.Util.EnumMap.Clear(); try { Transport transport = new Transport { KeepaliveFrame = Msg.Build(MsgType.Ping) }; transport.StartHost(CoopPlugin.Port.Value); _net = transport; Role = CoopRole.Host; StatusLine = "Hosting - waiting for a player..."; CoopPlugin.Log.LogInfo((object)$"Hosting on port {CoopPlugin.Port.Value}"); } catch (Exception ex) { ErrorLine = "Could not host: " + ex.Message; _net?.Stop(); _net = null; Role = CoopRole.None; } } public void Join(string ip) { ErrorLine = ""; if (Role != CoopRole.None) { ErrorLine = "Already in a session."; return; } if (InGameLevel()) { ErrorLine = "Join from the main menu (Title screen)."; return; } ip = (ip ?? "").Trim(); if (ip.Length == 0) { ErrorLine = "Enter the host's IP address."; return; } if (ModParity.RestartRequiredForJoin) { ErrorLine = "the host's card database was installed on this PC - RESTART the game before joining"; return; } CoopPlugin.LastJoinIP.Value = ip; Role = CoopRole.Client; GuestBorrowedWorld = true; StatusLine = "Connecting to " + ip + "..."; Transport net = new Transport { KeepaliveFrame = Msg.Build(MsgType.Ping) }; _net = net; int port = CoopPlugin.Port.Value; Thread thread = new Thread((ThreadStart)delegate { try { net.StartClient(ip, port); _mainThread.Enqueue(delegate { StatusLine = "Connected - requesting world..."; SendHello(); }); } catch (Exception ex) { Exception ex2 = ex; Exception e = ex2; _mainThread.Enqueue(delegate { ErrorLine = "Could not connect: " + e.Message; Shutdown(null); }); } }); thread.IsBackground = true; thread.Name = "CoopConnect"; thread.Start(); } public void Disconnect() { Shutdown("disconnected"); } public void SendEmote() { if (_net != null && Role != CoopRole.None) { Broadcast(MsgType.Emote, delegate(BinaryWriter bw) { bw.Write((byte)1); }); } } public void ForwardContribution(byte kind, float value) { if (Role == CoopRole.Client && _net != null) { Send(1, MsgType.EconContrib, delegate(BinaryWriter bw) { bw.Write(kind); bw.Write(value); }); } } public void ForwardSprayHit(Vector3 pos, float range, int potency) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (Role == CoopRole.Client && _net != null) { Send(1, MsgType.SprayHit, delegate(BinaryWriter bw) { bw.Write(pos.x); bw.Write(pos.y); bw.Write(pos.z); bw.Write(range); bw.Write(potency); }); } } public void ForwardCardDelta(CardData card, int amount, bool isAdd) { if (Role != CoopRole.None && _net != null && card != null && amount > 0) { _cardDeltaOutbox.Add(new PendingCard { IsAdd = isAdd, Amount = amount, Card = SnapshotCard(card) }); } } public void SendCardDeltaTo(int connId, CardData card, int amount, bool isAdd) { if (Role == CoopRole.Host && _net != null && card != null && amount > 0) { Send(connId, MsgType.CardDelta, delegate(BinaryWriter bw) { bw.Write(isAdd); bw.Write(amount); Msg.WriteCard(bw, card); }); } } public void ForwardGradedRemoval(CardData card) { if (Role != CoopRole.None && _net != null && card != null && card.cardGrade > 0) { Broadcast(MsgType.GradedRemove, delegate(BinaryWriter bw) { Msg.WriteCard(bw, card); }); } } public void ForwardOrder(int restockIndex, int count) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (Role != CoopRole.Client || _net == null) { return; } RestockData rd = null; try { rd = InventoryBase.GetRestockData(restockIndex); } catch { } if (rd == null) { CoopPlugin.Log.LogWarning((object)$"order: bad restock index {restockIndex}"); return; } float lineCost = 0f; try { lineCost = CPlayerData.GetItemCost(rd.itemType) * (float)RestockManager.GetMaxItemCountInBox(rd.itemType, rd.isBigBox) * (float)count; } catch { } Send(1, MsgType.OrderRequest, delegate(BinaryWriter bw) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Msg.WriteItemType(bw, rd.itemType); bw.Write(rd.isBigBox); bw.Write(rd.name ?? ""); bw.Write(count); bw.Write(lineCost); }); } public void ForwardLicense(int restockIndex) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected I4, but got Unknown if (Role == CoopRole.None || _net == null) { return; } RestockData val = null; try { val = InventoryBase.GetRestockData(restockIndex); } catch { } if (val == null) { return; } _lastLicenseBuyTime = Time.realtimeSinceStartupAsDouble; int itemType = (int)val.itemType; bool isBig = val.isBigBox; string rdName = val.name ?? ""; if (Role == CoopRole.Host) { Broadcast(MsgType.LicenseUnlock, delegate(BinaryWriter bw) { Msg.WriteItemType(bw, (EItemType)itemType); bw.Write(isBig); bw.Write(rdName); }); } else { Send(1, MsgType.LicenseUnlock, delegate(BinaryWriter bw) { Msg.WriteItemType(bw, (EItemType)itemType); bw.Write(isBig); bw.Write(rdName); }); } } private static int EplExtraCount() { try { if (!_eplProbed) { _eplProbed = true; _eplAssetsProp = AccessTools.TypeByName("EnhancedPrefabLoader.Core.EplRuntimeData")?.GetProperty("Assets", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); object obj = _eplAssetsProp?.GetValue(null); _eplItemLibProp = obj?.GetType().GetProperty("ItemLibrary", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); _eplRestockProp = ((obj == null) ? null : _eplItemLibProp?.GetValue(obj))?.GetType().GetProperty("RestockEntries", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); CoopPlugin.Log.LogInfo((object)((_eplRestockProp != null) ? "EPL catalog bridge active (virtual restock entries visible)" : "EPL catalog bridge inactive (EPL absent or its internals changed) - vanilla catalog only")); } object obj2 = _eplAssetsProp?.GetValue(null); object obj3 = ((obj2 == null) ? null : _eplItemLibProp?.GetValue(obj2)); return ((obj3 == null) ? null : (_eplRestockProp?.GetValue(obj3) as ICollection))?.Count ?? 0; } catch { return 0; } } private static int CatalogCount() { int num = 0; try { num = Inv().m_StockItemData_SO.m_RestockDataList.Count; } catch { } return num + EplExtraCount(); } private static RestockData CatalogAt(int i) { try { return InventoryBase.GetRestockData(i); } catch { return null; } } private static int ResolveRestockIndex(int itemType, bool isBig, string name, out bool sizeDiffers) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Invalid comparison between Unknown and I4 sizeDiffers = false; try { int num = CatalogCount(); for (int i = 0; i < num; i++) { RestockData val = CatalogAt(i); if (val != null && (int)val.itemType == itemType && val.isBigBox == isBig) { return i; } } if (!string.IsNullOrEmpty(name)) { for (int j = 0; j < num; j++) { RestockData val2 = CatalogAt(j); if (val2 != null && val2.name == name && val2.isBigBox == isBig) { return j; } } } sizeDiffers = true; for (int k = 0; k < num; k++) { RestockData val3 = CatalogAt(k); if (val3 != null && (int)val3.itemType == itemType) { return k; } } if (!string.IsNullOrEmpty(name)) { for (int l = 0; l < num; l++) { RestockData val4 = CatalogAt(l); if (val4 != null && val4.name == name) { return l; } } } } catch { } return -1; } private bool ApplyLicenseUnlock(int itemType, bool isBig, string name) { bool sizeDiffers; int num = ResolveRestockIndex(itemType, isBig, name, out sizeDiffers); if (num < 0) { CoopPlugin.Log.LogWarning((object)$"license unlock: no local product for type {itemType} big={isBig} '{name}'"); return false; } if (CPlayerData.GetIsItemLicenseUnlocked(num)) { return true; } GamePatches.ApplyingRemoteLicense = true; try { CPlayerData.SetUnlockItemLicense(num); try { AchievementManager.OnItemLicenseUnlocked((EItemType)itemType); } catch { } try { GameInstance.m_IsItemLicenseUnlocked = true; } catch { } try { if (itemType == 1) { TutorialManager.AddTaskValue((ETutorialTaskCondition)14, 1f); } } catch { } } finally { GamePatches.ApplyingRemoteLicense = false; } RefreshLicensePanels(); CoopPlugin.Log.LogInfo((object)$"license unlocked by partner: {(object)(EItemType)itemType} big={isBig}"); return true; } private static void RefreshLicensePanels() { try { RestockItemPanelUI[] array = Object.FindObjectsOfType<RestockItemPanelUI>(); foreach (RestockItemPanelUI obj in array) { if (!(FiPanelIndex?.GetValue(obj) is int num) || num < 0) { continue; } bool flag = false; try { flag = CPlayerData.GetIsItemLicenseUnlocked(num); } catch { } if (flag) { object? obj3 = FiPanelLicGrp?.GetValue(obj); object? obj4 = ((obj3 is GameObject) ? obj3 : null); if (obj4 != null) { ((GameObject)obj4).SetActive(false); } object? obj5 = FiPanelUIGrp?.GetValue(obj); object? obj6 = ((obj5 is GameObject) ? obj5 : null); if (obj6 != null) { ((GameObject)obj6).SetActive(true); } } } } catch { } } private void SendCatalogDigest() { try { int num = CatalogCount(); List<RestockData> entries = new List<RestockData>(num); for (int i = 0; i < num; i++) { RestockData val = CatalogAt(i); if (val != null && !string.IsNullOrEmpty(val.name)) { entries.Add(val); } } Send(1, MsgType.CatalogDigest, delegate(BinaryWriter bw) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) int num2 = Mathf.Min(entries.Count, 65535); bw.Write((ushort)num2); for (int j = 0; j < num2; j++) { Msg.WriteItemType(bw, entries[j].itemType); bw.Write(entries[j].isBigBox); bw.Write(Fnv(entries[j].name ?? "")); } }); } catch (Exception ex) { CoopPlugin.Log.LogWarning((object)("catalog digest: " + ex.Message)); } } private void CompareCatalogs(BinaryReader br, int connId) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected I4, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected I4, but got Unknown int num = br.ReadUInt16(); HashSet<long> hashSet = new HashSet<long>(); for (int i = 0; i < num; i++) { int type = (int)Msg.ReadItemType(br); bool big = br.ReadBoolean(); int nameHash = br.ReadInt32(); hashSet.Add(CatalogKey(type, big, nameHash)); } if ((Object)(object)Inv() == (Object)null) { return; } int num2 = CatalogCount(); int num3 = 0; int num4 = 0; List<string> list = new List<string>(); for (int j = 0; j < num2; j++) { RestockData val = CatalogAt(j); if (val == null || string.IsNullOrEmpty(val.name)) { continue; } if (hashSet.Contains(CatalogKey((int)val.itemType, val.isBigBox, Fnv(val.name)))) { num4++; continue; } num3++; if (list.Count < 6) { list.Add(val.name); } } int num5 = hashSet.Count - num4; if (num3 == 0 && num5 == 0) { CoopPlugin.Log.LogInfo((object)$"catalog check: identical ({num4} products)"); if (_catalogWarnedConns.Remove(connId)) { RegisterLine = "catalogs match now - the earlier warning was mod startup timing, all good"; RegisterLineTimer = 8f; Send(connId, MsgType.Toast, delegate(BinaryWriter bw) { bw.Write("catalogs match now - the earlier warning was mod startup timing, all good"); }); } return; } string value; string arg = (PeerNames.TryGetValue(connId, out value) ? value : "joiner"); string summary = $"heads-up: product catalogs differ ({num3} only on host, {num5} only on {arg}) - mismatched items can't be ordered; match your content packs"; CoopPlugin.Log.LogWarning((object)("catalog check: " + summary + ((list.Count > 0) ? (" | host-only e.g.: " + string.Join(" / ", list.ToArray())) : ""))); _catalogWarnedConns.Add(connId); RegisterLine = summary; RegisterLineTimer = 10f; Send(connId, MsgType.Toast, delegate(BinaryWriter bw) { bw.Write(summary); }); } private void LogCatalogCandidates(string name) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected I4, but got Unknown try { if (string.IsNullOrEmpty(name)) { return; } string text = name.Split(new char[1] { ' ' })[0]; int num = CatalogCount(); List<string> list = new List<string>(); for (int i = 0; i < num; i++) { if (list.Count >= 8) { break; } RestockData val = CatalogAt(i); if (val != null && val.name != null && val.name.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { list.Add($"{val.name} (type {(int)val.itemType}, big={val.isBigBox})"); } } CoopPlugin.Log.LogInfo((object)((list.Count > 0) ? ("similar host entries: " + string.Join(" | ", list.ToArray())) : ("no host entries resembling '" + text + "'"))); } catch { } } private static long CatalogKey(int type, bool big, int nameHash) { return (long)((ulong)((long)type << 33) ^ ((ulong)(uint)nameHash << 1)) ^ (long)(big ? 1 : 0); } private static int Fnv(string s) { uint num = 2166136261u; for (int i = 0; i < s.Length; i++) { num ^= s[i]; num *= 16777619; } return (int)num; } public void ForwardFurniture(int objType, Vector3 pos, Quaternion rot) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (Role == CoopRole.Client && _net != null) { Send(1, MsgType.FurnitureOrder, delegate(BinaryWriter bw) { Msg.WriteObjType(bw, (EObjectType)objType); bw.Write(pos.x); bw.Write(pos.y); bw.Write(pos.z); bw.Write(rot.x); bw.Write(rot.y); bw.Write(rot.z); bw.Write(rot.w); }); } } public void ForwardItemPrice(EItemType itemType, float price) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected I4, but got Unknown if (Role == CoopRole.Client && _net != null) { Send(1, MsgType.ItemPriceContrib, delegate(BinaryWriter bw) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Msg.WriteItemType(bw, itemType); bw.Write(price); }); _myItemPriceEdits[(int)itemType] = new MyItemPrice { Value = price, At = Time.realtimeSinceStartupAsDouble }; TrimMyItemPriceEdits(); } } public void ForwardCardPrice(CardData card, float price) { if (Role == CoopRole.None || _net == null || card == null) { return; } Broadcast(MsgType.CardPriceSet, delegate(BinaryWriter bw) { Msg.WriteCard(bw, card); bw.Write(price); }); if (Role == CoopRole.Client) { string text = CardPriceKey(card); if (text != null) { _myCardPrices[text] = new MyCardPrice { Card = SnapshotCard(card), Value = price, Acked = false, LastSend = Time.realtimeSinceStartupAsDouble, Attempts = 1 }; TrimMyCardPrices(); } } } private void TrimMyCardPrices() { while (_myCardPrices.Count > 1024) { string text = null; double num = double.MaxValue; foreach (KeyValuePair<string, MyCardPrice> myCardPrice in _myCardPrices) { if (myCardPrice.Value.Acked && myCardPrice.Value.LastSend < num) { num = myCardPrice.Value.LastSend; text = myCardPrice.Key; } } if (text == null) { foreach (KeyValuePair<string, MyCardPrice> myCardPrice2 in _myCardPrices) { if (myCardPrice2.Value.LastSend < num) { num = myCardPrice2.Value.LastSend; text = myCardPrice2.Key; } } } if (text != null) { _myCardPrices.Remove(text); continue; } break; } } private void TrimMyItemPriceEdits() { while (_myItemPriceEdits.Count > 256) { int key = 0; bool flag = false; double num = double.MaxValue; foreach (KeyValuePair<int, MyItemPrice> myItemPriceEdit in _myItemPriceEdits) { if (!flag || myItemPriceEdit.Value.At < num) { num = myItemPriceEdit.Value.At; key = myItemPriceEdit.Key; flag = true; } } if (flag) { _myItemPriceEdits.Remove(key); continue; } break; } } private bool HeldLocalItemPrice(int itemType, float incoming) { if (_myItemPriceEdits.Count == 0) { return false; } if (!_myItemPriceEdits.TryGetValue(itemType, out var value)) { return false; } if (Time.realtimeSinceStartupAsDouble - value.At >= 6.0) { _myItemPriceEdits.Remove(itemType); return false; } return Math.Abs(value.Value - incoming) > 0.0075f; } private void CardPriceRetryTick() { if (Role != CoopRole.Client || _net == null || _myCardPrices.Count == 0 || !InGameLevel()) { return; } double realtimeSinceStartupAsDouble = Time.realtimeSinceStartupAsDouble; _cardPriceRetryKeys.Clear(); foreach (KeyValuePair<string, MyCardPrice> myCardPrice in _myCardPrices) { if (!myCardPrice.Value.Acked && realtimeSinceStartupAsDouble - myCardPrice.Value.LastSend >= 3.0) { _cardPriceRetryKeys.Add(myCardPrice.Key); } } for (int i = 0; i < _cardPriceRetryKeys.Count; i++) { string text = _cardPriceRetryKeys[i]; if (!_myCardPrices.TryGetValue(text, out var value)) { continue; } if (value.Attempts >= 12) { _myCardPrices.Remove(text); CoopPlugin.Log.LogWarning((object)("card price for " + text + " never confirmed - keeping the local value until the host's next price sync")); continue; } CardData card = value.Card; float value2 = value.Value; Broadcast(MsgType.CardPriceSet, delegate(BinaryWriter bw) { Msg.WriteCard(bw, card); bw.Write(value2); }); value.LastSend = realtimeSinceStartupAsDouble; value.Attempts++; _myCardPrices[text] = value; } } private void Shutdown(string reason) { if (_net != null) { try { Broadcast(MsgType.Bye, null); } catch { } _net.Stop(); _net = null; } _avatars.Clear(); PeerNames.Clear(); _heldPurchases.Clear(); _deliveringHeld = false; _chargeVerdicts.Clear(); _lastDeclineToast.Clear(); _enumSyncSentTo.Clear(); _enumSyncSentToPeer.Clear(); CardShopCoop.Util.EnumMap.Clear(); ClearCardSetCache(); _clientPriced.Clear(); _incomingPriced.Clear(); _cardDeltaOutbox.Clear(); _batchRelayBuf.Clear(); _flushingCardDeltas = false; _binderRefreshPending = false; _deltaLogBuf.Clear(); _deltaAppliedThisFrame = 0; _pendingCardDeltas.Clear(); _pendingCardPrices.Clear(); _myCardPrices.Clear(); _cardPriceRetryKeys.Clear(); _cardPriceRetryTimer = 0f; _myItemPriceEdits.Clear(); _priceWarnedKeys.Clear(); _dispatchBuf.Clear(); _dispatchSeen.Clear(); _saveBuf = null; _saveExpected = -1; _pendingSave = null; _bundleBuf = null; _bundleExpected = -1; _worldRequested = false; _hasLastPos = false; _lastCoinSent = double.MinValue; _lastPriceHash = 0; _cardPriceBuf.Clear(); _lastCardPriceHash = 0; _cardPriceHealBeat = 0f; _cardPriceHealTimer = -2.1f; _lastProgressSent = long.MinValue; _world.Reset(); _npcs.Reset(); _cardShelves.Reset(); _objMoves.Reset(); _boxes.Reset(); _population.Reset(); _registerMirror.Reset(); ModulesReset(); PromptLine = ""; _lastShopNameSent = null; _steamLobby.Leave(); IsSteamSession = false; HostPassword = ""; _joinPassword = ""; _selfId = -1; _relayIds.Clear(); _pendingKicks.Clear(); Application.runInBackground = false; Role = CoopRole.None; if (!InGameLevel()) { GuestBorrowedWorld = false; } if (reason != null) { StatusLine = "Not connected (" + reason + ")"; CoopPlugin.Log.LogInfo((object)("Session ended: " + reason)); } } private void Send(int connId, MsgType type, Action<BinaryWriter> write) { FlushCardDeltaOutbox(); _net?.Send(connId, Msg.Build(type, write)); } private void Broadcast(MsgType type, Action<BinaryWriter> write) { FlushCardDeltaOutbox(); _net?.Broadcast(Msg.Build(type, write)); } private void BroadcastTransient(MsgType type, Action<BinaryWriter> write) { FlushCardDeltaOutbox(); _net?.BroadcastTransient(Msg.Build(type, write)); } private void ResolveHeldPurchases(int connId, bool deliver) { if (_heldPurchases.Count == 0) { return; } bool flag = false; int num = 0; while (num < _heldPurchases.Count) { if (_heldPurchases[num].Msg.ConnId != connId) { num++; continue; } InMsg msg = _heldPurchases[num].Msg; _heldPurchases.RemoveAt(num); if (deliver) { _deliveringHeld = true; try { Dispatch(msg); } finally { _deliveringHeld = false; } continue; } CoopPlugin.Log.LogInfo((object)$"purchase ({msg.Type}) from conn {connId} cancelled - its charge was declined (shared wallet short)"); if (!flag) { flag = true; _lastDeclineToast[connId] = Time.realtimeSinceStartupAsDouble; Send(connId, MsgType.Toast, delegate(BinaryWriter bw) { bw.Write("not enough money - the purchase was cancelled"); }); } } } private PurchaseGate GateProduct(InMsg msg) { if (_deliveringHeld) { return PurchaseGate.Process; } double realtimeSinceStartupAsDouble = Time.realtimeSinceStartupAsDouble; if (_chargeVerdicts.TryGetValue(msg.ConnId, out var value) && realtimeSinceStartupAsDouble - value.At < (value.Accepted ? 1.0 : 10.0)) { if (value.Accepted) { return PurchaseGate.Process; } CoopPlugin.Log.LogInfo((object)$"purchase ({msg.Type}) from conn {msg.ConnId} dropped - its charge was declined (shared wallet short)"); if (!_lastDeclineToast.TryGetValue(msg.ConnId, out var value2) || realtimeSinceStartupAsDouble - value2 >= 1.0) { _lastDeclineToast[msg.ConnId] = realtimeSinceStartupAsDouble; Send(msg.ConnId, MsgType.Toast, delegate(BinaryWriter bw) { bw.Write("not enough money - the purchase was cancelled"); }); } return PurchaseGate.Drop; } _heldPurchases.Add(new HeldPurchase { Msg = msg, At = realtimeSinceStartupAsDouble }); return PurchaseGate.Hold; } private void PumpHeldPurchases() { if (_heldPurchases.Count == 0) { return; } double realtimeSinceStartupAsDouble = Time.realtimeSinceStartupAsDouble; while (_heldPurchases.Count > 0 && realtimeSinceStartupAsDouble - _heldPurchases[0].At > 1.5) { InMsg msg = _heldPurchases[0].Msg; _heldPurchases.RemoveAt(0); CoopPlugin.Log.LogInfo((object)$"held purchase ({msg.Type}) from conn {msg.ConnId} saw no charge within 1.5s - delivering (fail-open)"); _deliveringHeld = true; try { Dispatch(msg); } finally { _deliveringHeld = false; } } } internal static bool NativeTextInputFocused() { EventSystem current = EventSystem.current; GameObject val = ((current != null) ? current.currentSelectedGameObject : null); if ((Object)(object)val == (Object)null) { return false; } TMP_InputField component = val.GetComponent<TMP_InputField>(); if ((Object)(object)component != (Object)null) { return component.isFocused; } return false; } private void Update() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_08ce: Unknown result type (might be due to invalid IL or missing references) //IL_08df: Unknown result type (might be due to invalid IL or missing references) //IL_08f0: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) Action result; while (_mainThread.TryDequeue(out result)) { try { result(); } catch (Exception ex) { CoopPlugin.Log.LogError((object)ex); } } if (GuestBorrowedWorld && Role == CoopRole.None && !InGameLevel()) { GuestBorrowedWorld = false; } if (Role == CoopRole.Client && InGameLevel()) { RecoverStuckHoldBox(); } AutoTick(Time.deltaTime); if (Input.GetKeyDown(CoopPlugin.UiToggleKey.Value)) { _ui.Visible = !_ui.Visible; } if (Role != CoopRole.None && Input.GetKeyDown(CoopPlugin.EmoteKey.Value) && !CoopUI.TextFieldFocused) { SendEmote(); } if (_serveThrottle > 0f) { _serveThrottle -= Time.deltaTime; } if (RegisterLineTimer > 0f) { RegisterLineTimer -= Time.deltaTime; if (RegisterLineTimer <= 0f) { RegisterLine = ""; } } bool serveTap = Input.GetKeyDown(CoopPlugin.ServeKey.Value); if (serveTap && Role == CoopRole.Client && (CoopUI.TextFieldFocused || NativeTextInputFocused())) { CoopPlugin.Log.LogInfo((object)("serve key ignored (a text field has focus - " + (CoopUI.TextFieldFocused ? "co-op window" : "game input") + ")")); } if (Role == CoopRole.Client && _serveThrottle <= 0f && InGameLevel() && (serveTap || Input.GetKey(CoopPlugin.ServeKey.Value)) && !CoopUI.TextFieldFocused && !NativeTextInputFocused()) { _serveThrottle = 0.25f; Guarded("serve", delegate { //IL_0020: Unknown result type (might be due to invalid IL or missing references) Transform val2 = ResolvePlayer(); int idx = (((Object)(object)val2 != (Object)null) ? RegisterServe.FindNearestCounter(val2.position, CoopPlugin.ServeReach.Value, !serveTap) : (-1)); if (idx < 0 || !_trades.HasOffer(idx)) { if (idx < 0) { if (serveTap) { RegisterLine = "walk up to the register first"; RegisterLineTimer = 2f; } } else { Send(1, MsgType.ServeRequest, delegate(BinaryWriter bw) { bw.Write(idx); }); } } }); } if (Role == CoopRole.Host && HostServeKeyEnabled && _serveThrottle <= 0f && InGameLevel() && (serveTap || Input.GetKey(CoopPlugin.ServeKey.Value)) && !CoopUI.TextFieldFocused && !NativeTextInputFocused()) { _serveThrottle = 0.25f; Guarded("host-serve", delegate { //IL_0019: Unknown result type (might be due to invalid IL or missing references) Transform val2 = ResolvePlayer(); int num10 = (((Object)(object)val2 != (Object)null) ? RegisterServe.FindNearestCounter(val2.position, CoopPlugin.ServeReach.Value, !serveTap) : (-1)); if (num10 < 0 || !_trades.HasOffer(num10)) { if (num10 < 0) { if (serveTap) { RegisterLine = "walk up to the register first"; RegisterLineTimer = 2f; } } else { byte[] scanEcho; string text4 = RegisterServe.Serve(num10, CoopPlugin.PlayerName.Value, out scanEcho); if (!string.IsNullOrEmpty(text4)) { RegisterLine = text4; RegisterLi