/// <summary>
        /// Returns whether a transfer is allowed to succeed or not.
        /// </summary>
        public static bool TransferMaySucceed(XBankAccount FromAccount, XBankAccount ToAccount, Money MoneyNeeded, Journal.BankAccountTransferOptions Options) {
            if (FromAccount == null || ToAccount == null) {
                return false;
            }

            return ((FromAccount.IsSystemAccount || FromAccount.IsPluginAccount || ((Options & Journal.BankAccountTransferOptions.AllowDeficitOnNormalAccount) == Journal.BankAccountTransferOptions.AllowDeficitOnNormalAccount)) || (FromAccount.Balance >= MoneyNeeded && MoneyNeeded > 0));
        }
        /// <summary>
        /// Adds an XBankAccount to the bank account collection.
        /// </summary>
        public static XBankAccount AddBankAccount(XBankAccount Account) {
            lock (__staticLock) {
                Account.BankAccountK = RandomString(8);

                XmlJournal.XPathSelectElement("/Journal/BankAccounts").Add((XElement)Account);

                return Account;
            }
        }
 /// <summary>
 /// Asynchronously transfers to another account.
 /// </summary>
 public Task<BankTransferEventArgs> TransferToAsync(XBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage) {
     Guid profile = SEconomyPlugin.Profiler.Enter(string.Format("transferAsync: {0} to {1}", this.UserAccountName, ToAccount.UserAccountName));
     return Task.Factory.StartNew<BankTransferEventArgs>(() => {
         BankTransferEventArgs args = TransferTo(ToAccount, Amount, Options, TransactionMessage, JournalMessage);
         return args;
     }).ContinueWith((task) => {
         SEconomyPlugin.Profiler.ExitLog(profile);
         return task.Result;
     });
 }
        /// <summary>
        /// Adds an XBankAccount to the bank account collection.
        /// </summary>
        public static XBankAccount AddBankAccount(XBankAccount Account)
        {
            lock (__staticLock) {
                Account.BankAccountK = RandomString(8);

                XmlJournal.XPathSelectElement("/Journal/BankAccounts").Add((XElement)Account);

                return(Account);
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Asynchronously transfers to another account.
        /// </summary>
        public Task <BankTransferEventArgs> TransferToAsync(XBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string Message = "")
        {
            Guid profile = SEconomyPlugin.Profiler.Enter(string.Format("transferAsync: {0} to {1}", this.UserAccountName, ToAccount.UserAccountName));

            return(Task.Factory.StartNew <BankTransferEventArgs>(() => {
                BankTransferEventArgs args = TransferTo(ToAccount, Amount, Options, UseProfiler: false, Message: Message);
                return args;
            }).ContinueWith((task) => {
                SEconomyPlugin.Profiler.ExitLog(profile);
                return task.Result;
            }));
        }
        /// <summary>
        /// Returns a world account for the current running world.  If it does not exist, one gets created and then returned.
        /// </summary>
        public static XBankAccount EnsureWorldAccountExists()
        {
            XBankAccount worldAccount = null;

            lock (__staticLock) {
                //World account matches the current world, ignore.
                if (SEconomyPlugin.WorldAccount != null && SEconomyPlugin.WorldAccount.WorldID == Terraria.Main.worldID)
                {
                    return(null);
                }

                if (Terraria.Main.worldID > 0)
                {
                    worldAccount = (from i in BankAccounts
                                    where (i.Flags & Journal.BankAccountFlags.SystemAccount) == Journal.BankAccountFlags.SystemAccount &&
                                    (i.Flags & Journal.BankAccountFlags.PluginAccount) == 0 &&
                                    i.WorldID == Terraria.Main.worldID
                                    select i).FirstOrDefault();

                    //world account does not exist for this world ID, create one
                    if (worldAccount == null)
                    {
                        //This account is always enabled, locked to the world it's in and a system account (ie. can run into deficit) but not a plugin account
                        XBankAccount newWorldAcc = new XBankAccount("SYSTEM", Terraria.Main.worldID, Journal.BankAccountFlags.Enabled | Journal.BankAccountFlags.LockedToWorld | Journal.BankAccountFlags.SystemAccount, "World account for world " + Terraria.Main.worldName);

                        worldAccount = AddBankAccount(newWorldAcc);
                    }

                    if (worldAccount != null && !string.IsNullOrEmpty(worldAccount.BankAccountK))
                    {
                        //Is this account listed as enabled?
                        bool accountEnabled = (worldAccount.Flags & Journal.BankAccountFlags.Enabled) == Journal.BankAccountFlags.Enabled;

                        if (!accountEnabled)
                        {
                            TShockAPI.Log.ConsoleError("The world account for world " + Terraria.Main.worldName + " is disabled.  Currency will not work for this game.");
                            return(null);
                        }
                    }
                    else
                    {
                        TShockAPI.Log.ConsoleError("There was an error loading the bank account for this world.  Currency will not work for this game.");
                    }
                }
            }

            return(worldAccount);
        }
        XTransaction FinishEndTransaction(string SourceBankTransactionKey, XBankAccount ToAccount, Money Amount, string Message) {
            XTransaction destTran = new XTransaction(Amount);

            destTran.BankAccountFK = ToAccount.BankAccountK;
            destTran.Flags = Journal.BankAccountTransactionFlags.FundsAvailable;
            destTran.TransactionDateUtc = DateTime.UtcNow;
            destTran.Amount = Amount;
            destTran.BankAccountTransactionFK = SourceBankTransactionKey;

            if (!string.IsNullOrEmpty(Message)) {
                destTran.Message = Message;
            }

            lock (TransactionJournal.XmlJournal) {
                return Journal.TransactionJournal.AddTransaction(destTran);
            }
        }
Esempio n. 8
0
        XTransaction FinishEndTransaction(string SourceBankTransactionKey, XBankAccount ToAccount, Money Amount, string Message)
        {
            XTransaction destTran = new XTransaction(Amount);

            destTran.BankAccountFK            = ToAccount.BankAccountK;
            destTran.Flags                    = Journal.BankAccountTransactionFlags.FundsAvailable;
            destTran.TransactionDateUtc       = DateTime.UtcNow;
            destTran.Amount                   = Amount;
            destTran.BankAccountTransactionFK = SourceBankTransactionKey;

            if (!string.IsNullOrEmpty(Message))
            {
                destTran.Message = Message;
            }

            lock (TransactionJournal.XmlJournal) {
                return(Journal.TransactionJournal.AddTransaction(destTran));
            }
        }
        /// <summary>
        /// Deletes all transactions for an account, effectively returning their balance back to 0.
        /// </summary>
        public static void ResetAccountTransactions(string BankAccountK)
        {
            lock (__staticLock) {
                do
                {
                    XElement trans = XmlJournal.XPathSelectElement(string.Format("/Journal/Transactions/Transaction[@BankAccountFK=\"{0}\"]", BankAccountK));

                    if (trans == null)
                    {
                        break;
                    }

                    var      sourceTransactionFK = trans.Attribute("BankAccountTransactionFK").Value;
                    XElement sourceTrans         = XmlJournal.XPathSelectElement(string.Format("/Journal/Transactions/Transaction[@BankAccountTransactionK=\"{0}\"]", sourceTransactionFK));
                    trans.Remove();
                    sourceTrans.Remove();
                } while (true);

                XBankAccount account = GetBankAccount(BankAccountK);
                account.SyncBalanceAsync();
            }
        }
Esempio n. 10
0
        /// <summary>
        /// Occurs when a player's bank account flags change
        /// </summary>
        void BankAccount_BankAccountFlagsChanged(object sender, Journal.BankAccountChangedEventArgs e)
        {
            Journal.XBankAccount  bankAccount = sender as Journal.XBankAccount;
            Economy.EconomyPlayer player      = GetEconomyPlayerByBankAccountNameSafe(bankAccount.UserAccountName);


            //You can technically make payments to anyone even if they are offline.
            //This serves as a basic online check as we don't give a f**k about informing
            //an offline person that their account has been disabled or not.
            if (player != null)
            {
                bool enabled = (e.NewFlags & Journal.BankAccountFlags.Enabled) == Journal.BankAccountFlags.Enabled;

                TSPlayer caller = TShock.Players[e.CallerID];
                if (player.TSPlayer.Name == caller.Name)
                {
                    player.TSPlayer.SendInfoMessageFormat("bank: Your bank account has been {0}d.", enabled ? "enable" : "disable");
                }
                else
                {
                    player.TSPlayer.SendInfoMessageFormat("bank: {1} {0}d your account.", enabled ? "enable" : "disable", caller.Name);
                }
            }
        }
        /// <summary>
        /// Returns a world account for the current running world.  If it does not exist, one gets created and then returned.
        /// </summary>
        public static XBankAccount EnsureWorldAccountExists() {
            XBankAccount worldAccount = null;

            lock (__staticLock) {
                //World account matches the current world, ignore.
                if (SEconomyPlugin.WorldAccount != null && SEconomyPlugin.WorldAccount.WorldID == Terraria.Main.worldID) {
                    return null;
                }

                if (Terraria.Main.worldID > 0) {


                    worldAccount = (from i in BankAccounts
                                    where (i.Flags & Journal.BankAccountFlags.SystemAccount) == Journal.BankAccountFlags.SystemAccount
                                       && (i.Flags & Journal.BankAccountFlags.PluginAccount) == 0
                                       && i.WorldID == Terraria.Main.worldID
                                    select i).FirstOrDefault();

                    //world account does not exist for this world ID, create one
                    if (worldAccount == null) {
                        //This account is always enabled, locked to the world it's in and a system account (ie. can run into deficit) but not a plugin account
                        XBankAccount newWorldAcc = new XBankAccount("SYSTEM", Terraria.Main.worldID, Journal.BankAccountFlags.Enabled | Journal.BankAccountFlags.LockedToWorld | Journal.BankAccountFlags.SystemAccount, "World account for world " + Terraria.Main.worldName);

                        worldAccount = AddBankAccount(newWorldAcc);
                    }

                    if (worldAccount != null && !string.IsNullOrEmpty(worldAccount.BankAccountK)) {
                        //Is this account listed as enabled?
                        bool accountEnabled = (worldAccount.Flags & Journal.BankAccountFlags.Enabled) == Journal.BankAccountFlags.Enabled;

                        if (!accountEnabled) {
                            TShockAPI.Log.ConsoleError("The world account for world " + Terraria.Main.worldName + " is disabled.  Currency will not work for this game.");
                            return null;
                        }
                    } else {
                        TShockAPI.Log.ConsoleError("There was an error loading the bank account for this world.  Currency will not work for this game.");
                    }
                }
            }

            return worldAccount;
        }
Esempio n. 12
0
        /// <summary>
        /// Transfers money from this account to the destination account, if negative, takes money from the destination account into this account.
        /// </summary>
        public BankTransferEventArgs TransferTo(XBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, bool UseProfiler = true, string Message = "")
        {
            lock (__tranlock) {
                BankTransferEventArgs args = new BankTransferEventArgs();
                Guid profile = Guid.Empty;

                if (UseProfiler)
                {
                    profile = SEconomyPlugin.Profiler.Enter(string.Format("transfer: {0} to {1}", this.UserAccountName, ToAccount.UserAccountName));
                }

                if (ToAccount != null && TransferMaySucceed(this, ToAccount, Amount, Options))
                {
                    args.Amount            = Amount;
                    args.SenderAccount     = this;
                    args.ReceiverAccount   = ToAccount;
                    args.TransferOptions   = Options;
                    args.TransferSucceeded = false;

                    //insert the source negative transaction
                    XTransaction sourceTran = BeginSourceTransaction(Amount, Message);
                    if (sourceTran != null && !string.IsNullOrEmpty(sourceTran.BankAccountTransactionK))
                    {
                        //insert the destination inverse transaction
                        XTransaction destTran = FinishEndTransaction(sourceTran.BankAccountTransactionK, ToAccount, Amount, Message);

                        if (destTran != null && !string.IsNullOrEmpty(destTran.BankAccountTransactionK))
                        {
                            //perform the double-entry binding
                            BindTransactions(ref sourceTran, ref destTran);

                            args.TransactionID = sourceTran.BankAccountTransactionK;

                            //update balances
                            this.Balance      += (Amount * (-1));
                            ToAccount.Balance += Amount;

                            //transaction complete
                            args.TransferSucceeded = true;
                        }
                    }
                }
                else
                {
                    args.TransferSucceeded = false;

                    if (!ToAccount.IsSystemAccount && !ToAccount.IsPluginAccount)
                    {
                        if (Amount < 0)
                        {
                            this.Owner.TSPlayer.SendErrorMessageFormat("Invalid amount.");
                        }
                        else
                        {
                            this.Owner.TSPlayer.SendErrorMessageFormat("You need {0} more money to make this payment.", ((Money)(this.Balance - Amount)).ToLongString());
                        }
                    }
                }

                //raise the transfer event
                OnBankTransferComplete(args);

                if (UseProfiler)
                {
                    SEconomyPlugin.Profiler.ExitLog(profile);
                }

                return(args);
            }
        }
Esempio n. 13
0
 /// <summary>
 /// Returns whether a transfer is allowed to succeed or not.
 /// </summary>
 public static bool TransferMaySucceed(XBankAccount FromAccount, XBankAccount ToAccount, Money MoneyNeeded, Journal.BankAccountTransferOptions Options)
 {
     return((FromAccount.IsSystemAccount || FromAccount.IsPluginAccount || ((Options & Journal.BankAccountTransferOptions.AllowDeficitOnNormalAccount) == Journal.BankAccountTransferOptions.AllowDeficitOnNormalAccount)) || (FromAccount.Balance >= MoneyNeeded && MoneyNeeded > 0));
 }
        /// <summary>
        /// Transfers money from this account to the destination account, if negative, takes money from the destination account into this account.
        /// </summary>
        public BankTransferEventArgs TransferTo(XBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage) {
            BankTransferEventArgs args = new BankTransferEventArgs();
            Guid profile = Guid.Empty;

            try {
                lock (__tranlock) {
                  
                    if (ToAccount != null) {
                        if (TransferMaySucceed(this, ToAccount, Amount, Options)) {
                            if (SEconomyPlugin.Configuration.EnableProfiler) {
                                profile = SEconomyPlugin.Profiler.Enter(string.Format("transfer: {0} to {1}", !string.IsNullOrEmpty(this.UserAccountName) ? this.UserAccountName : "Unknown", ToAccount != null && !string.IsNullOrEmpty(ToAccount.UserAccountName) ? ToAccount.UserAccountName : "Unknown"));
                            }
                            args.Amount = Amount;
                            args.SenderAccount = this;
                            args.ReceiverAccount = ToAccount;
                            args.TransferOptions = Options;
                            args.TransferSucceeded = false;
                            args.TransactionMessage = TransactionMessage;

                            //insert the source negative transaction
                            XTransaction sourceTran = BeginSourceTransaction(Amount, JournalMessage);
                            if (sourceTran != null && !string.IsNullOrEmpty(sourceTran.BankAccountTransactionK)) {
                                //insert the destination inverse transaction
                                XTransaction destTran = FinishEndTransaction(sourceTran.BankAccountTransactionK, ToAccount, Amount, JournalMessage);

                                if (destTran != null && !string.IsNullOrEmpty(destTran.BankAccountTransactionK)) {
                                    //perform the double-entry binding
                                    BindTransactions(ref sourceTran, ref destTran);

                                    args.TransactionID = sourceTran.BankAccountTransactionK;

                                    //update balances
                                    this.Balance += (Amount * (-1));
                                    ToAccount.Balance += Amount;

                                    //transaction complete
                                    args.TransferSucceeded = true;
                                }
                            }
                        } else {
                            args.TransferSucceeded = false;

                            //concept: ??????
                            //if the amount coming from "this" account is a negative then the "sender account" needs to know the transfer failed.
                            //if the amount coming from "this" acount is a positive then the "reciever account" needs to know the transfer failed.

                            if (!ToAccount.IsSystemAccount && !ToAccount.IsPluginAccount) {
                                if (this.Owner != null) {
                                    if (Amount < 0) {
                                        this.Owner.TSPlayer.SendErrorMessageFormat("Invalid amount.");
                                    } else {
                                        this.Owner.TSPlayer.SendErrorMessageFormat("You need {0} more money to make this payment.", ((Money)(this.Balance - Amount)).ToLongString());
                                    }
                                }
                            }
                        }
                    }

                    //raise the transfer event
                    OnBankTransferComplete(args);

                    if (SEconomyPlugin.Configuration.EnableProfiler) {
                        SEconomyPlugin.Profiler.ExitLog(profile);
                    }
                }

            } catch (Exception ex) {
                args.Exception = ex;
                args.TransferSucceeded = false;
            }

            return args;
        }
        /// <summary>
        /// Compresses all transactions into one line.  Doing this is going to remove all transaction history but you gain space and processing speed
        /// </summary>
        public static void SquashJournal()
        {
            int       bankAccountCount = BankAccounts.Count();
            int       tranCount        = Transactions.Count();
            XDocument newJournal       = NewJournal();

            bool responsibleForTurningBackupsBackOn = false;

            Console.WriteLine("seconomy xml: beginning Squash");

            if (SEconomyPlugin.BackupCanRun == true)
            {
                SEconomyPlugin.BackupCanRun        = false;
                responsibleForTurningBackupsBackOn = true;
            }

            for (int i = 0; i < bankAccountCount; i++)
            {
                XBankAccount account = BankAccounts.ElementAtOrDefault(i);
                if (account != null)
                {
                    //update account balance
                    account.SyncBalance();

                    string line = string.Format("\r [squash] {0:p} {1}", (double)i / (double)bankAccountCount, account.UserAccountName);
                    SEconomyPlugin.FillWithSpaces(ref line);

                    Console.Write(line);

                    //copy the bank account from the old journal into the new one
                    newJournal.Element("Journal").Element("BankAccounts").Add((XElement)account);

                    //Add the squished summary
                    XTransaction transSummary = new XTransaction(account.Balance);
                    transSummary.BankAccountTransactionK = RandomString(13);
                    transSummary.BankAccountFK           = account.BankAccountK;
                    transSummary.Flags              = BankAccountTransactionFlags.FundsAvailable | BankAccountTransactionFlags.Squashed;
                    transSummary.Message            = "Transaction squash";
                    transSummary.TransactionDateUtc = DateTime.UtcNow;

                    newJournal.Element("Journal").Element("Transactions").Add((XElement)transSummary);
                }
            }

            //abandon the old journal and assign the squashed one
            XmlJournal = newJournal;

            Console.WriteLine("re-syncing online accounts.");

            foreach (XBankAccount account in BankAccounts)
            {
                XBankAccount runtimeAccount = GetBankAccount(account.BankAccountK);
                if (runtimeAccount != null && runtimeAccount.Owner != null)
                {
                    Console.WriteLine("re-syncing {0}", runtimeAccount.Owner.TSPlayer.Name);
                    runtimeAccount.SyncBalance();
                }
            }

            SaveXml(Configuration.JournalPath);

            //the backups could already have been disabled by something else.  We don't want to be the ones turning it back on
            if (responsibleForTurningBackupsBackOn)
            {
                SEconomyPlugin.BackupCanRun = true;
            }
        }