Skip to content
267 changes: 155 additions & 112 deletions Essentials/Commands/EcoModule.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using Sandbox;
using Sandbox.Engine.Multiplayer;
using Sandbox.Game.GameSystems.BankingAndCurrency;
using Sandbox.Game.World;
using Torch;
using Torch.API.Managers;
using Torch.Commands;
using Torch.Commands.Permissions;
using Torch.Managers.ChatManager;
using Torch.Mod;
using Torch.Mod.Messages;
using VRage.Game.ModAPI;
using VRageRender.Utils;

namespace Essentials.Commands
{
Expand All @@ -25,158 +16,148 @@ public class EcoModule : CommandModule {

[Command("give", "Add a specified anount of credits into a users account. Use '*' to affect all players")]
[Permission(MyPromoteLevel.Admin)]
public void EcoGive(string Player, long amount) {
if (Player != "*") {
var p = Utilities.GetPlayerByNameOrId(Player);
if (p == null) {
Context.Respond("Player is not online or cannot be found!");
return;
}
p.TryGetBalanceInfo(out long balance);
Context.Respond($"new bal will be {balance + amount:#,##0}");
p.RequestChangeBalance(amount);
ModCommunication.SendMessageTo(new NotificationMessage($"{amount:#,##0} credits have been added to your virtual account", 10000, "Blue"), p.SteamUserId);
public void EcoGive(string player, long amount, bool onlyOnline = false, bool excludeNpcs = true) {

if(!TryFindPlayerIdentities(player, onlyOnline, excludeNpcs, out List<long> foundIdentities)) {
Context.Respond("Player cannot be found!");
return;
}
else {
foreach (var p in MySession.Static.Players.GetAllPlayers()) {
long IdentityID = MySession.Static.Players.TryGetIdentityId(p.SteamId);
MyBankingSystem.ChangeBalance(IdentityID, amount);
ModCommunication.SendMessageTo(new NotificationMessage($"{amount:#,##0} credits have been added to your virtual account", 10000, "Blue"), p.SteamId);
}

int changedIdentities = 0;

foreach (long identityId in foundIdentities) {

ChangeBalance(identityId, amount);

ulong steamId = Utilities.GetSteamId(identityId);

ModCommunication.SendMessageTo(new NotificationMessage($"{amount:#,##0} credits have been added to your virtual account", 10000, "Blue"), steamId);

changedIdentities++;
}
Context.Respond($"{amount:#,##0} credits given to account(s)");

Context.Respond($"{amount:#,##0} credits given to {changedIdentities:#,##0} account(s)");
}

[Command("take", "Take a specified anount of credits from a users account. Use '*' to affect all players")]
[Permission(MyPromoteLevel.Admin)]
public void EcoTake(string Player, long amount) {
if (Player != "*") {
var p = Utilities.GetPlayerByNameOrId(Player);
if (p == null) {
Context.Respond("Player is not online or cannot be found!");
return;
}
long changefactor = 0 - amount;
p.RequestChangeBalance(changefactor);
ModCommunication.SendMessageTo(new NotificationMessage($"{amount:#,##0} credits have been taken to your virtual account", 10000, "Blue"), p.SteamUserId);
public void EcoTake(string player, long amount, bool onlyOnline = false, bool excludeNpcs = true) {

if (!TryFindPlayerIdentities(player, onlyOnline, excludeNpcs, out List<long> foundIdentities)) {
Context.Respond("Player cannot be found!");
return;
}
else {
foreach (var p in MySession.Static.Players.GetAllPlayers()) {
long IdentityID = MySession.Static.Players.TryGetIdentityId(p.SteamId);
long balance = MyBankingSystem.GetBalance(IdentityID);
MyBankingSystem.ChangeBalance(IdentityID, -amount);
ModCommunication.SendMessageTo(new NotificationMessage($"{amount:#,##0} credits have been taken to your virtual account", 10000, "Blue"), p.SteamId);
}

int changedIdentities = 0;

foreach (long identityId in foundIdentities) {

ChangeBalance(identityId, -amount);

ulong steamId = Utilities.GetSteamId(identityId);

ModCommunication.SendMessageTo(new NotificationMessage($"{amount:#,##0} credits have been taken from your virtual account", 10000, "Blue"), steamId);

changedIdentities++;
}
Context.Respond($"{amount:#,##0} credits taken from account(s)");

Context.Respond($"{amount:#,##0} credits taken from {changedIdentities:#,##0} account(s)");
}

[Command("set", "Set a users account to a specifed balance. Use '*' to affect all players")]
[Permission(MyPromoteLevel.Admin)]
public void EcoSet(string Player, long amount) {
if (Player != "*") {
var p = Utilities.GetPlayerByNameOrId(Player);
if (p == null) {
Context.Respond("Player is not online or cannot be found!");
return;
}
p.TryGetBalanceInfo(out long balance);
long difference = (balance - amount);
p.RequestChangeBalance(-difference);
ModCommunication.SendMessageTo(new NotificationMessage($"Your balance has been set to {amount:#,##0} credits!", 10000, "Blue"), p.SteamUserId);
public void EcoSet(string player, long amount, bool onlyOnline = false, bool excludeNpcs = true) {

if (!TryFindPlayerIdentities(player, onlyOnline, excludeNpcs, out List<long> foundIdentities)) {
Context.Respond("Player cannot be found!");
return;
}
else {
foreach (var p in MySession.Static.Players.GetAllPlayers()) {
long IdentityID = MySession.Static.Players.TryGetIdentityId(p.SteamId);
long balance = MyBankingSystem.GetBalance(IdentityID);
long difference = (balance - amount);
MyBankingSystem.ChangeBalance(IdentityID, -difference);
ModCommunication.SendMessageTo(new NotificationMessage($"Your balance has been set to {amount:#,##0} credits!", 10000, "Blue"), p.SteamId);
}

int changedIdentities = 0;

foreach (long identityId in foundIdentities) {

long balance = MyBankingSystem.GetBalance(identityId);

ChangeBalance(identityId, -(balance - amount));

ulong steamId = Utilities.GetSteamId(identityId);

ModCommunication.SendMessageTo(new NotificationMessage($"Your balance has been set to {amount:#,##0} credits!", 10000, "Blue"), steamId);

changedIdentities++;
}
Context.Respond($"Balance(s) set to {amount:#,##0}");

Context.Respond($"Balance(s) set to {amount:#,##0} on {changedIdentities:#,##0} accounts");
}

[Command("reset", "Reset the credits in a users account to 10,000. Use '*' to affect all players")]
[Permission(MyPromoteLevel.Admin)]
public void EcoReset(string Player) {
if (Player != "*") {
var p = Utilities.GetPlayerByNameOrId(Player);
if (p == null) {
Context.Respond("Player is not online or cannot be found!");
return;
}
p.TryGetBalanceInfo(out long balance);
long difference = (balance - 10000);
p.RequestChangeBalance(-difference);
ModCommunication.SendMessageTo(new NotificationMessage($"Your balance has been reset to 10,000 credits!", 10000, "Blue"), p.SteamUserId);
}
else {
foreach (var p in MySession.Static.Players.GetAllPlayers()) {
long IdentityID = MySession.Static.Players.TryGetIdentityId(p.SteamId);
long balance = MyBankingSystem.GetBalance(IdentityID);
long difference = (balance - 10000);
MyBankingSystem.ChangeBalance(IdentityID, -difference);
ModCommunication.SendMessageTo(new NotificationMessage($"Your balance has been reset to 10,000 credits!", 10000, "Blue"), p.SteamId);
}
}
Context.Respond("Balance(s) reset to 10,000 credits");
public void EcoReset(string player, bool onlyOnline = false, bool excludeNpcs = true) {
EcoSet(player, 10_000, onlyOnline, excludeNpcs);
}

[Command("top", "Return a list of each players balance on the server sorted from highest to lowest")]
[Permission(MyPromoteLevel.None)]
public void EcoTop() {
public void EcoTop(bool onlyOnline = false, bool excludeNpcs = true) {

TryFindPlayerIdentities("*", onlyOnline, excludeNpcs, out List<long> foundIdentities);

var players = MySession.Static.Players;

Dictionary<MyIdentity, long> balances = new Dictionary<MyIdentity, long>();
foreach (long identityId in foundIdentities) {

var identity = players.TryGetIdentity(identityId);
long balance = MyBankingSystem.GetBalance(identityId);

balances[identity] = balance;
}

StringBuilder ecodata = new StringBuilder();
ecodata.AppendLine("Summary of balanaces accross the server");
Dictionary<ulong, long> balances = new Dictionary<ulong, long>();
foreach (var p in MySession.Static.Players.GetAllPlayers()) {

long IdentityID = MySession.Static.Players.TryGetIdentityId(p.SteamId);
long balance = MyBankingSystem.GetBalance(IdentityID);

/*
* Add or Update. We have seen that it is possible to have
* two players with the same SteamID but different SerialIDs.
*
* Those also had different identities. But one of which was dead.
* TryGetIdentityId() Returned the same value in both cases. So no damage done if
* Value is just overwritten.
*/
balances[p.SteamId] = balance;
}
var sorted = balances.OrderByDescending(x => x.Value).ThenBy(x => x.Key);

var sorted = balances.OrderByDescending(x => x.Value).ThenBy(x => x.Key.DisplayName);
foreach (var value in sorted) {
var test = MySession.Static.Players.TryGetIdentityNameFromSteamId(value.Key);
ecodata.AppendLine($"Player: {MySession.Static.Players.TryGetIdentityNameFromSteamId(value.Key)} - Balance: {value.Value:#,##0}");

var identity = value.Key;

ecodata.AppendLine($"Player: {identity.DisplayName} - Balance: {value.Value:#,##0}");
}

if (Context.Player == null) {
Context.Respond(ecodata.ToString());
return;
}

ModCommunication.SendMessageTo(new DialogMessage("Public balance list", "List of players and their credit balances", ecodata.ToString()), Context.Player.SteamUserId);
}

[Command("check", "Check the balance of a specific player")]
[Permission(MyPromoteLevel.None)]
public void EcoCheck(string Player) {

var p = Utilities.GetIdentityByNameOrIds(Player);
if (p == null) {
Context.Respond("Player cannot be found!");
return;
}

long balance = MyBankingSystem.GetBalance(p.IdentityId);

Context.Respond($"{p.DisplayName}'s balance is {balance:#,##0} credits");
}

[Command("pay")]
[Permission(MyPromoteLevel.None)]
public void EcoPay(string Player, long amount) {

if (Context.Player == null) {
Context.Respond("Console cannot execute this command");
return;
}

/* We are purposely keeping the online check in this method. Otherwise it could cause confusion with players. */
var p = Utilities.GetPlayerByNameOrId(Player);
if (p == null) {
Context.Respond("Player is not online or cannot be found!");
Expand All @@ -186,18 +167,80 @@ public void EcoPay(string Player, long amount) {
var fromIdentitiyId = Context.Player.Identity.IdentityId;
var toIdentitiyId = p.Identity.IdentityId;

if(fromIdentitiyId == toIdentitiyId) {
if (fromIdentitiyId == toIdentitiyId) {
Context.Respond("You cannot pay yourself!");
return;
}

var finalFromBalance = MyBankingSystem.GetBalance(fromIdentitiyId) - amount;
var finalToBalance = MyBankingSystem.GetBalance(toIdentitiyId) + amount;


if(finalFromBalance < 0) {
Context.Respond($"Sorry, but you are short {-finalFromBalance:#,##0} credits!");
return;
}

MyBankingSystem.RequestTransfer_BroadcastToClients(Context.Player.Identity.IdentityId, p.Identity.IdentityId, amount, finalFromBalance, finalToBalance);
ModCommunication.SendMessageTo(new NotificationMessage($"Your have recieved {amount:#,##0} credits from {Context.Player.DisplayName}!", 10000, "Blue"),p.SteamUserId);
ModCommunication.SendMessageTo(new NotificationMessage($"Your have sent {amount:#,##0} credits to {p.DisplayName}!", 10000, "Blue"),Context.Player.SteamUserId);
ModCommunication.SendMessageTo(new NotificationMessage($"Your have recieved {amount:#,##0} credits from {Context.Player.DisplayName}!", 10000, "Blue"), p.SteamUserId);
ModCommunication.SendMessageTo(new NotificationMessage($"Your have sent {amount:#,##0} credits to {p.DisplayName}!", 10000, "Blue"), Context.Player.SteamUserId);
}

/// <summary>
/// This method changes the balance of the given identity by the passed amount.
/// If the amount is positive the player receives credits. If it is negative, the player loses credits.
///
/// If the amount taken from a users account is greater than the amount the user has, the accounts balance is set to 0, since negative balances are not possible.
/// </summary>
private void ChangeBalance(long identityId, long amount) {

long balance = MyBankingSystem.GetBalance(identityId);

if (balance + amount < 0)
amount = -balance;

MyBankingSystem.ChangeBalance(identityId, amount);
}

/// <summary>
/// This method take all identities of the server and assembles a list with the respective identityIDs.
/// It is possible to filter this list to not contain NPCs or only contain players that are currently online.
///
/// Returns true if the given playerName exists and could be found, or the playerName is "*" false otherwise.
/// Even if true is returned the list of foundIdentities can be empty if the online or npc filters got applied.
/// </summary>
private bool TryFindPlayerIdentities(string playerName, bool onlyOnline, bool excludeNpcs, out List<long> foundIdentities) {

var relevantIdentities = new List<long>();
var players = MySession.Static.Players;

if (playerName != "*") {

var identity = Utilities.GetIdentityByNameOrIds(playerName);

if (identity == null) {
foundIdentities = relevantIdentities;
return false;
}

relevantIdentities.Add(identity.IdentityId);

} else {

relevantIdentities.AddRange(players.GetAllIdentities()
.Select(identity => identity.IdentityId));
}

IEnumerable<long> identitiesToCheck = relevantIdentities;

if (onlyOnline)
identitiesToCheck = identitiesToCheck.Where(identityId => players.IsPlayerOnline(identityId));

if (excludeNpcs)
identitiesToCheck = identitiesToCheck.Where(identityId => !players.IdentityIsNpc(identityId));

foundIdentities = identitiesToCheck.ToList();

return true;
}
}
}
7 changes: 6 additions & 1 deletion Essentials/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public static IMyIdentity GetIdentityByNameOrIds(string playerNameOrIds)

if (ulong.TryParse(playerNameOrIds, out ulong steamId))
{
ulong id = MySession.Static.Players.TryGetSteamId(identity.IdentityId);
ulong id = GetSteamId(identity.IdentityId);
if (id == steamId)
return identity;
}
Expand Down Expand Up @@ -152,6 +152,11 @@ public static IMyPlayer GetPlayerByNameOrId(string nameOrPlayerId)
return null;
}

public static ulong GetSteamId(long identityId)
{
return MySession.Static.Players.TryGetSteamId(identityId);
}

public static int GetOnlinePlayerCount()
{
var result = 0;
Expand Down