1
0
mirror of https://github.com/RaidMax/IW4M-Admin.git synced 2025-06-10 15:20:48 -05:00

fixes for new polling setup

update database model for alias (nullable ip)
heartbeats now send ip to master server
This commit is contained in:
RaidMax
2018-11-25 20:00:36 -06:00
parent 1cfe7047a2
commit df5fbba22c
28 changed files with 1257 additions and 408 deletions

View File

@ -37,11 +37,25 @@ namespace SharedLibraryCore.Commands
{
if ((await (E.Owner.Manager.GetClientService() as ClientService).GetOwners()).Count == 0)
{
var oldPermission = E.Origin.Level;
E.Origin.Level = EFClient.Permission.Owner;
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_OWNER_SUCCESS"]);
// so setpassword/login works
E.Owner.Manager.GetPrivilegedClients().Add(E.Origin.ClientId, E.Origin);
await E.Owner.Manager.GetClientService().Update(E.Origin);
var e = new GameEvent()
{
Type = GameEvent.EventType.ChangePermission,
Origin = E.Origin,
Target = E.Origin,
Owner = E.Owner,
Extra = new Change()
{
PreviousValue = oldPermission.ToString(),
NewValue = E.Origin.Level.ToString()
}
};
E.Owner.Manager.GetEventHandler().AddEvent(e);
}
else
{
@ -494,17 +508,6 @@ namespace SharedLibraryCore.Commands
await E.Owner.Manager.GetClientService().Update(E.Target);
}
try
{
E.Owner.Manager.GetPrivilegedClients().Add(E.Target.ClientId, E.Target);
}
catch (Exception)
{
// this updates their privilege level to the webfront claims
E.Owner.Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target;
}
var e = new GameEvent()
{
Origin = E.Origin,

View File

@ -22,7 +22,7 @@ namespace SharedLibraryCore.Database
static string _ConnectionString;
static string _provider;
private static string _migrationPluginDirectory = @"X:\IW4MAdmin\BUILD\Plugins\";
private static readonly string _migrationPluginDirectory = @"X:\IW4MAdmin\BUILD\Plugins\";
public DatabaseContext(DbContextOptions<DatabaseContext> opt) : base(opt) { }
@ -110,6 +110,7 @@ namespace SharedLibraryCore.Database
modelBuilder.Entity<EFAlias>(ent =>
{
ent.Property(a => a.IPAddress).IsRequired(false);
ent.HasIndex(a => a.IPAddress);
ent.Property(a => a.Name).HasMaxLength(24);
ent.HasIndex(a => a.Name);
@ -123,14 +124,15 @@ namespace SharedLibraryCore.Database
// adapted from
// https://aleemkhan.wordpress.com/2013/02/28/dynamically-adding-dbset-properties-in-dbcontext-for-entity-framework-code-first/
#if DEBUG
string pluginDir = _migrationPluginDirectory;
#else
string pluginDir = Path.Join(Utilities.OperatingDirectory, "Plugins");
#endif
IEnumerable<string> directoryFiles = Directory.GetFiles(pluginDir).Where(f => f.EndsWith(".dll"));
#if DEBUG == TRUE
foreach (string dllPath in Directory.GetFiles(_migrationPluginDirectory).Where(f => f.EndsWith(".dll")))
#else
foreach (string dllPath in directoryFiles)
#endif
{
Assembly library;
try

View File

@ -16,7 +16,7 @@ namespace SharedLibraryCore.Database.Models
[MaxLength(24)]
public string Name { get; set; }
[Required]
public int IPAddress { get; set; }
public int? IPAddress { get; set; }
[Required]
public DateTime DateAdded { get; set; }
}

View File

@ -44,14 +44,14 @@ namespace SharedLibraryCore.Database.Models
set { CurrentAlias.Name = value; }
}
[NotMapped]
public virtual int IPAddress
public virtual int? IPAddress
{
get { return CurrentAlias.IPAddress; }
set { CurrentAlias.IPAddress = value; }
}
[NotMapped]
public string IPAddressString => new System.Net.IPAddress(BitConverter.GetBytes(IPAddress)).ToString();
public string IPAddressString => IPAddress.ConvertIPtoString();
[NotMapped]
public virtual IDictionary<int, long> LinkedAccounts { get; set; }

View File

@ -208,38 +208,5 @@ namespace SharedLibraryCore
return this;
});
}
/// <summary>
/// determine whether an event should be delayed or not
/// applies only to the origin entity
/// </summary>
/// <param name="queuedEvent">event to determine status for</param>
/// <returns>true if event should be delayed, false otherwise</returns>
public static bool ShouldOriginEventBeDelayed(GameEvent queuedEvent)
{
return queuedEvent.Origin != null &&
(queuedEvent.Origin.State != EFClient.ClientState.Connected &&
// we want to allow join and quit events
queuedEvent.Type != EventType.Connect &&
queuedEvent.Type != EventType.Join &&
queuedEvent.Type != EventType.Quit &&
queuedEvent.Type != EventType.Disconnect &&
// we don't care about unknown events
queuedEvent.Origin.NetworkId != 0);
}
/// <summary>
/// determine whether an event should be delayed or not
/// applies only to the target entity
/// </summary>
/// <param name="queuedEvent">event to determine status for</param>
/// <returns>true if event should be delayed, false otherwise</returns>
public static bool ShouldTargetEventBeDelayed(GameEvent queuedEvent)
{
return (queuedEvent.Target != null && queuedEvent.Target.ClientNumber != -1) &&
(queuedEvent.Target.State != EFClient.ClientState.Connected &&
queuedEvent.Target.NetworkId != 0 &&
queuedEvent.Origin?.ClientId != 1);
}
}
}

View File

@ -0,0 +1,690 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using SharedLibraryCore.Database;
namespace SharedLibraryCore.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20181125193243_MakeClientIPNullable")]
partial class MakeClientIPNullable
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.4-rtm-31024");
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
{
b.Property<int>("SnapshotId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ClientId");
b.Property<int>("CurrentSessionLength");
b.Property<double>("CurrentStrain");
b.Property<int>("CurrentViewAngleId");
b.Property<int>("Deaths");
b.Property<double>("Distance");
b.Property<double>("EloRating");
b.Property<int>("HitDestinationId");
b.Property<int>("HitLocation");
b.Property<int>("HitOriginId");
b.Property<int>("HitType");
b.Property<int>("Hits");
b.Property<int>("Kills");
b.Property<int>("LastStrainAngleId");
b.Property<double>("SessionAngleOffset");
b.Property<double>("SessionSPM");
b.Property<int>("SessionScore");
b.Property<double>("StrainAngleBetween");
b.Property<int>("TimeSinceLastEvent");
b.Property<int>("WeaponId");
b.Property<DateTime>("When");
b.HasKey("SnapshotId");
b.HasIndex("ClientId");
b.HasIndex("CurrentViewAngleId");
b.HasIndex("HitDestinationId");
b.HasIndex("HitOriginId");
b.HasIndex("LastStrainAngleId");
b.ToTable("EFACSnapshot");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
{
b.Property<long>("KillId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("AttackerId");
b.Property<int>("Damage");
b.Property<int?>("DeathOriginVector3Id");
b.Property<int>("DeathType");
b.Property<double>("Fraction");
b.Property<int>("HitLoc");
b.Property<bool>("IsKill");
b.Property<int?>("KillOriginVector3Id");
b.Property<int>("Map");
b.Property<int>("ServerId");
b.Property<int>("VictimId");
b.Property<int?>("ViewAnglesVector3Id");
b.Property<double>("VisibilityPercentage");
b.Property<int>("Weapon");
b.Property<DateTime>("When");
b.HasKey("KillId");
b.HasIndex("AttackerId");
b.HasIndex("DeathOriginVector3Id");
b.HasIndex("KillOriginVector3Id");
b.HasIndex("ServerId");
b.HasIndex("VictimId");
b.HasIndex("ViewAnglesVector3Id");
b.ToTable("EFClientKills");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
{
b.Property<long>("MessageId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ClientId");
b.Property<string>("Message");
b.Property<int>("ServerId");
b.Property<DateTime>("TimeSent");
b.HasKey("MessageId");
b.HasIndex("ClientId");
b.HasIndex("ServerId");
b.HasIndex("TimeSent");
b.ToTable("EFClientMessages");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
{
b.Property<int>("RatingHistoryId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ClientId");
b.HasKey("RatingHistoryId");
b.HasIndex("ClientId");
b.ToTable("EFClientRatingHistory");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
{
b.Property<int>("ClientId");
b.Property<int>("ServerId");
b.Property<bool>("Active");
b.Property<int>("Deaths");
b.Property<double>("EloRating");
b.Property<int>("Kills");
b.Property<double>("MaxStrain");
b.Property<double>("RollingWeightedKDR");
b.Property<double>("SPM");
b.Property<double>("Skill");
b.Property<int>("TimePlayed");
b.Property<double>("VisionAverage");
b.HasKey("ClientId", "ServerId");
b.HasIndex("ServerId");
b.ToTable("EFClientStatistics");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
{
b.Property<int>("HitLocationCountId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ClientId")
.HasColumnName("EFClientStatistics_ClientId");
b.Property<int>("HitCount");
b.Property<float>("HitOffsetAverage");
b.Property<int>("Location");
b.Property<float>("MaxAngleDistance");
b.Property<int>("ServerId")
.HasColumnName("EFClientStatistics_ServerId");
b.HasKey("HitLocationCountId");
b.HasIndex("ServerId");
b.HasIndex("ClientId", "ServerId");
b.ToTable("EFHitLocationCounts");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
{
b.Property<int>("RatingId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ActivityAmount");
b.Property<bool>("Newest");
b.Property<double>("Performance");
b.Property<int>("Ranking");
b.Property<int>("RatingHistoryId");
b.Property<int?>("ServerId");
b.Property<DateTime>("When");
b.HasKey("RatingId");
b.HasIndex("Performance");
b.HasIndex("Ranking");
b.HasIndex("RatingHistoryId");
b.HasIndex("ServerId");
b.HasIndex("When");
b.ToTable("EFRating");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
{
b.Property<int>("ServerId");
b.Property<bool>("Active");
b.Property<int>("Port");
b.HasKey("ServerId");
b.ToTable("EFServers");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
{
b.Property<int>("StatisticId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ServerId");
b.Property<long>("TotalKills");
b.Property<long>("TotalPlayTime");
b.HasKey("StatisticId");
b.HasIndex("ServerId");
b.ToTable("EFServerStatistics");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
{
b.Property<int>("AliasId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<DateTime>("DateAdded");
b.Property<int?>("IPAddress");
b.Property<int>("LinkId");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(24);
b.HasKey("AliasId");
b.HasIndex("IPAddress");
b.HasIndex("LinkId");
b.HasIndex("Name");
b.ToTable("EFAlias");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
{
b.Property<int>("AliasLinkId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.HasKey("AliasLinkId");
b.ToTable("EFAliasLinks");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b =>
{
b.Property<int>("ChangeHistoryId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<string>("Comment")
.HasMaxLength(128);
b.Property<string>("CurrentValue");
b.Property<int>("OriginEntityId");
b.Property<string>("PreviousValue");
b.Property<int>("TargetEntityId");
b.Property<DateTime>("TimeChanged");
b.Property<int>("TypeOfChange");
b.HasKey("ChangeHistoryId");
b.ToTable("EFChangeHistory");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
{
b.Property<int>("ClientId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("AliasLinkId");
b.Property<int>("Connections");
b.Property<int>("CurrentAliasId");
b.Property<DateTime>("FirstConnection");
b.Property<DateTime>("LastConnection");
b.Property<int>("Level");
b.Property<bool>("Masked");
b.Property<long>("NetworkId");
b.Property<string>("Password");
b.Property<string>("PasswordSalt");
b.Property<int>("TotalConnectionTime");
b.HasKey("ClientId");
b.HasIndex("AliasLinkId");
b.HasIndex("CurrentAliasId");
b.HasIndex("NetworkId")
.IsUnique();
b.ToTable("EFClients");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
{
b.Property<int>("MetaId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<int>("ClientId");
b.Property<DateTime>("Created");
b.Property<string>("Extra");
b.Property<string>("Key")
.IsRequired();
b.Property<DateTime>("Updated");
b.Property<string>("Value")
.IsRequired();
b.HasKey("MetaId");
b.HasIndex("ClientId");
b.ToTable("EFMeta");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
{
b.Property<int>("PenaltyId")
.ValueGeneratedOnAdd();
b.Property<bool>("Active");
b.Property<string>("AutomatedOffense");
b.Property<DateTime?>("Expires");
b.Property<int>("LinkId");
b.Property<int>("OffenderId");
b.Property<string>("Offense")
.IsRequired();
b.Property<int>("PunisherId");
b.Property<int>("Type");
b.Property<DateTime>("When");
b.HasKey("PenaltyId");
b.HasIndex("LinkId");
b.HasIndex("OffenderId");
b.HasIndex("PunisherId");
b.ToTable("EFPenalties");
});
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
{
b.Property<int>("Vector3Id")
.ValueGeneratedOnAdd();
b.Property<int?>("EFACSnapshotSnapshotId");
b.Property<float>("X");
b.Property<float>("Y");
b.Property<float>("Z");
b.HasKey("Vector3Id");
b.HasIndex("EFACSnapshotSnapshotId");
b.ToTable("Vector3");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
.WithMany()
.HasForeignKey("CurrentViewAngleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
.WithMany()
.HasForeignKey("HitDestinationId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
.WithMany()
.HasForeignKey("HitOriginId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
.WithMany()
.HasForeignKey("LastStrainAngleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
.WithMany()
.HasForeignKey("AttackerId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin")
.WithMany()
.HasForeignKey("DeathOriginVector3Id");
b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin")
.WithMany()
.HasForeignKey("KillOriginVector3Id");
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
.WithMany()
.HasForeignKey("VictimId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles")
.WithMany()
.HasForeignKey("ViewAnglesVector3Id");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics")
.WithMany("HitLocations")
.HasForeignKey("ClientId", "ServerId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
{
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
.WithMany("Ratings")
.HasForeignKey("RatingHistoryId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
{
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
.WithMany("Children")
.HasForeignKey("LinkId")
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
.WithMany()
.HasForeignKey("AliasLinkId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
.WithMany()
.HasForeignKey("CurrentAliasId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany("Meta")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
.WithMany("ReceivedPenalties")
.HasForeignKey("LinkId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
.WithMany("ReceivedPenalties")
.HasForeignKey("OffenderId")
.OnDelete(DeleteBehavior.Restrict);
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
.WithMany("AdministeredPenalties")
.HasForeignKey("PunisherId")
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
{
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot")
.WithMany("PredictedViewAngles")
.HasForeignKey("EFACSnapshotSnapshotId");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,85 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace SharedLibraryCore.Migrations
{
public partial class MakeClientIPNullable : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.Sqlite")
{
migrationBuilder.Sql(@"PRAGMA foreign_keys = 0;
CREATE TABLE sqlitestudio_temp_table AS SELECT *
FROM EFAlias;
DROP TABLE EFAlias;
CREATE TABLE EFAlias (
AliasId INTEGER NOT NULL
CONSTRAINT PK_EFAlias PRIMARY KEY AUTOINCREMENT,
Active INTEGER NOT NULL,
DateAdded TEXT NOT NULL,
IPAddress INTEGER,
LinkId INTEGER NOT NULL,
Name TEXT NOT NULL,
CONSTRAINT FK_EFAlias_EFAliasLinks_LinkId FOREIGN KEY (
LinkId
)
REFERENCES EFAliasLinks (AliasLinkId) ON DELETE RESTRICT
);
INSERT INTO EFAlias (
AliasId,
Active,
DateAdded,
IPAddress,
LinkId,
Name
)
SELECT AliasId,
Active,
DateAdded,
IPAddress,
LinkId,
Name
FROM sqlitestudio_temp_table;
DROP TABLE sqlitestudio_temp_table;
CREATE INDEX IX_EFAlias_LinkId ON EFAlias (
""LinkId""
);
CREATE INDEX IX_EFAlias_IPAddress ON EFAlias(
""IPAddress""
);
CREATE INDEX IX_EFAlias_Name ON EFAlias(
""Name""
);
PRAGMA foreign_keys = 1;
");
}
else
{
migrationBuilder.AlterColumn<int>(
name: "IPAddress",
table: "EFAlias",
nullable: true,
oldClrType: typeof(int));
}
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "IPAddress",
table: "EFAlias",
nullable: false,
oldClrType: typeof(int),
oldNullable: true);
}
}
}

View File

@ -317,7 +317,7 @@ namespace SharedLibraryCore.Migrations
b.Property<DateTime>("DateAdded");
b.Property<int>("IPAddress");
b.Property<int?>("IPAddress");
b.Property<int>("LinkId");

View File

@ -80,7 +80,6 @@ namespace SharedLibraryCore.Database.Models
{
{ "_reportCount", 0 }
};
CurrentAlias = CurrentAlias ?? new EFAlias();
}
public override string ToString()
@ -405,7 +404,7 @@ namespace SharedLibraryCore.Database.Models
public void OnConnect()
{
var loc = Utilities.CurrentLocalization.LocalizationIndex;
#if !DEBUG
if (Name.Length < 3)
{
CurrentServer.Logger.WriteDebug($"Kicking {this} because their name is too short");
@ -440,8 +439,6 @@ namespace SharedLibraryCore.Database.Models
LastConnection = DateTime.UtcNow;
Connections += 1;
#endif
}
public async Task OnDisconnect()
@ -452,24 +449,11 @@ namespace SharedLibraryCore.Database.Models
await CurrentServer.Manager.GetClientService().Update(this);
}
public async Task OnJoin(int ipAddress)
public async Task OnJoin(int? ipAddress)
{
// todo: fix this up
var existingAlias = AliasLink.Children
.FirstOrDefault(a => a.Name == Name && a.IPAddress == ipAddress);
IPAddress = ipAddress;
if (existingAlias == null)
{
CurrentServer.Logger.WriteDebug($"Client {this} has connected previously under a different ip/name");
CurrentAlias = new EFAlias()
{
IPAddress = ipAddress,
Name = Name
};
}
await CurrentServer.Manager.GetClientService().Update(this);
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
var loc = Utilities.CurrentLocalization.LocalizationIndex;
var activePenalties = await CurrentServer.Manager.GetPenaltyService().GetActivePenaltiesAsync(AliasLinkId, ipAddress);
@ -519,6 +503,19 @@ namespace SharedLibraryCore.Database.Models
Kick($"{loc["SERVER_TB_REMAIN"]} ({(currentBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})", autoKickClient);
}
}
else
{
var e = new GameEvent()
{
Type = GameEvent.EventType.Join,
Origin = this,
Target = this,
Owner = CurrentServer
};
CurrentServer.Manager.GetEventHandler().AddEvent(e);
}
}
[NotMapped]
@ -557,18 +554,7 @@ namespace SharedLibraryCore.Database.Models
public int Score { get; set; }
[NotMapped]
public bool IsBot { get; set; }
//private int _ipaddress;
//public override int IPAddress
//{
// get => _ipaddress;
// set => _ipaddress = value;
//}
//private string _name;
//public override string Name
//{
// get => _name;
// set => _name = value;
//}
[NotMapped]
public ClientState State { get; set; }
[NotMapped]

View File

@ -313,7 +313,7 @@ namespace SharedLibraryCore
public bool RestartRequested { get; set; }
// Internal
protected string IP;
public string IP { get; protected set; }
protected int Port;
protected string FSGame;
protected int NextMessage;

View File

@ -1,15 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using SharedLibraryCore.Database;
using SharedLibraryCore.Database.Models;
using System.Linq.Expressions;
using SharedLibraryCore.Objects;
using Microsoft.EntityFrameworkCore;
using SharedLibraryCore.Dtos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using static SharedLibraryCore.Database.Models.EFClient;
namespace SharedLibraryCore.Services
@ -21,55 +17,28 @@ namespace SharedLibraryCore.Services
{
using (var context = new DatabaseContext())
{
bool hasExistingAlias = false;
// get all aliases by IP
var aliases = await context.Aliases
.Include(a => a.Link)
.Where(a => a.IPAddress == entity.IPAddress)
.ToListAsync();
// see if they have a matching IP + Name but new NetworkId
var existingAlias = aliases.FirstOrDefault(a => a.Name == entity.Name);
// if existing alias matches link them
EFAliasLink aliasLink = existingAlias?.Link;
// if no exact matches find the first IP that matches
aliasLink = aliasLink ?? aliases.FirstOrDefault()?.Link;
// if no exact or IP matches, create new link
aliasLink = aliasLink ?? new EFAliasLink()
{
Active = true,
};
// this has to be set here because we can't evalute it properly later
hasExistingAlias = existingAlias != null;
// if no existing alias create new alias
existingAlias = existingAlias ?? new EFAlias()
{
Active = true,
DateAdded = DateTime.UtcNow,
IPAddress = entity.IPAddress,
Link = aliasLink,
Name = entity.Name,
};
var client = new EFClient()
{
Active = true,
// set the level to the level of the existing client if they have the same IP + Name but new NetworkId
// fixme: issues?
Level = hasExistingAlias ?
(await context.Clients.Where(c => c.AliasLinkId == existingAlias.LinkId)
.OrderByDescending(c => c.Level)
.FirstOrDefaultAsync())?.Level ?? Permission.User :
Permission.User,
Level = Permission.User,
FirstConnection = DateTime.UtcNow,
Connections = 1,
LastConnection = DateTime.UtcNow,
Masked = false,
NetworkId = entity.NetworkId,
AliasLink = aliasLink,
CurrentAlias = existingAlias,
AliasLink = new EFAliasLink()
{
Active = false
},
};
client.CurrentAlias = new Alias()
{
Name = entity.Name,
Link = client.AliasLink,
DateAdded = DateTime.UtcNow,
// the first time a client is created, we may not have their ip,
// so we create a temporary alias
Active = false
};
context.Clients.Add(client);
@ -79,6 +48,101 @@ namespace SharedLibraryCore.Services
}
}
public async Task UpdateAlias(EFClient entity)
{
using (var context = new DatabaseContext())
{
context.Attach(entity);
string name = entity.Name;
int? ip = entity.IPAddress;
bool hasExistingAlias = false;
// get all aliases by IP
var aliases = await context.Aliases
.Include(a => a.Link)
.Where(a => a.IPAddress != null && a.IPAddress == ip)
.ToListAsync();
// see if they have a matching IP + Name but new NetworkId
var existingAlias = aliases.FirstOrDefault(a => a.Name == name);
// if existing alias matches link them
EFAliasLink aliasLink = existingAlias?.Link;
// if no exact matches find the first IP that matches
aliasLink = aliasLink ?? aliases.FirstOrDefault()?.Link;
// if no exact or IP matches, create new link
aliasLink = aliasLink ?? new EFAliasLink();
// this has to be set here because we can't evalute it properly later
hasExistingAlias = existingAlias != null;
if (hasExistingAlias && !entity.AliasLink.Active)
{
// we want to delete the temporary alias
context.Entry(entity.CurrentAlias).State = EntityState.Deleted;
entity.CurrentAlias = null;
// we want to delete the temporary alias link
context.Entry(entity.AliasLink).State = EntityState.Deleted;
entity.AliasLink = null;
// they have an existing alias so assign it
entity.CurrentAlias = existingAlias;
entity.AliasLink = aliasLink;
await context.SaveChangesAsync();
}
// update the temporary alias to permanent one
else if (!entity.AliasLink.Active)
{
// we want to track the current alias and link
var alias = context.Update(entity.CurrentAlias).Entity;
var _aliasLink = context.Update(entity.AliasLink).Entity;
alias.Active = true;
alias.IPAddress = ip;
alias.Name = name;
_aliasLink.Active = true;
existingAlias = alias;
aliasLink = _aliasLink;
}
// if no existing alias create new alias
existingAlias = existingAlias ?? new EFAlias()
{
DateAdded = DateTime.UtcNow,
IPAddress = ip,
Link = aliasLink,
Name = name,
};
var iqExistingPermission = context.Clients.Where(c => c.AliasLinkId == existingAlias.LinkId)
.OrderByDescending(client => client.Level)
.Select(c => new EFClient() { Level = c.Level });
entity.Level = hasExistingAlias ?
(await iqExistingPermission.FirstOrDefaultAsync())?.Level ?? Permission.User :
Permission.User;
#if DEBUG
string sql = iqExistingPermission.AsQueryable().ToSql();
#endif
if (entity.CurrentAlias != existingAlias ||
entity.AliasLink != aliasLink)
{
entity.CurrentAlias = existingAlias;
entity.AliasLink = aliasLink;
context.Update(entity);
}
await context.SaveChangesAsync();
}
}
public async Task<EFClient> Delete(EFClient entity)
{
using (var context = new DatabaseContext())
@ -132,13 +196,17 @@ namespace SharedLibraryCore.Services
var foundClient = await iqClient.FirstOrDefaultAsync();
if (foundClient == null)
{
return null;
}
foundClient.Client.LinkedAccounts = new Dictionary<int, long>();
// todo: find out the best way to do this
// I'm doing this here because I don't know the best way to have multiple awaits in the query
foreach (var linked in foundClient.LinkedAccounts)
{
foundClient.Client.LinkedAccounts.Add(linked.ClientId, linked.NetworkId);
}
return foundClient.Client;
}
@ -168,7 +236,7 @@ namespace SharedLibraryCore.Services
var client = context.Clients
.Include(c => c.AliasLink)
.Include(c => c.CurrentAlias)
.Single(e => e.ClientId == entity.ClientId);
.First(e => e.ClientId == entity.ClientId);
// if their level has been changed
if (entity.Level != client.Level)
@ -191,7 +259,7 @@ namespace SharedLibraryCore.Services
{
client.CurrentAlias = new EFAlias()
{
Active = true,
Active = entity.CurrentAlias.IPAddress.HasValue ? true : false,
DateAdded = DateTime.UtcNow,
IPAddress = entity.CurrentAlias.IPAddress,
Name = entity.CurrentAlias.Name,
@ -202,6 +270,8 @@ namespace SharedLibraryCore.Services
else
{
client.CurrentAliasId = entity.CurrentAliasId;
client.IPAddress = entity.IPAddress;
client.Name = entity.Name;
}
// set remaining non-navigation properties that may have been updated
@ -219,7 +289,10 @@ namespace SharedLibraryCore.Services
// this is set so future updates don't trigger a new alias add
if (entity.CurrentAlias.AliasId == 0)
{
entity.CurrentAlias.AliasId = client.CurrentAlias.AliasId;
}
return client;
}
}
@ -228,24 +301,27 @@ namespace SharedLibraryCore.Services
public async Task<IList<EFClient>> GetOwners()
{
using (var context = new DatabaseContext())
{
return await context.Clients
.Where(c => c.Level == Permission.Owner)
.ToListAsync();
}
}
public async Task<IList<ClientInfo>> GetPrivilegedClients()
public async Task<List<EFClient>> GetPrivilegedClients()
{
using (var context = new DatabaseContext(disableTracking: true))
{
var iqClients = from client in context.Clients
where client.Level >= Permission.Trusted
where client.Active
select new ClientInfo()
select new EFClient()
{
CurrentAlias = client.CurrentAlias,
ClientId = client.ClientId,
Name = client.CurrentAlias.Name,
LinkId = client.AliasLinkId,
Level = client.Level
Level = client.Level,
Password = client.Password,
PasswordSalt = client.PasswordSalt
};
#if DEBUG == true
@ -294,20 +370,16 @@ namespace SharedLibraryCore.Services
public async Task<int> GetTotalClientsAsync()
{
using (var context = new DatabaseContext(true))
{
return await context.Clients
.CountAsync();
}
}
public Task<EFClient> CreateProxy()
{
throw new NotImplementedException();
}
public async Task<int> GetTotalPlayTime()
{
using (var context = new DatabaseContext(true))
return await context.Clients.SumAsync(c => c.TotalConnectionTime);
}
#endregion
}
}

View File

@ -213,7 +213,7 @@ namespace SharedLibraryCore.Services
}
}
public async Task<List<EFPenalty>> GetActivePenaltiesAsync(int linkId, int ip = 0)
public async Task<List<EFPenalty>> GetActivePenaltiesAsync(int linkId, int? ip = null)
{
var now = DateTime.UtcNow;
@ -221,7 +221,7 @@ namespace SharedLibraryCore.Services
{
var iqPenalties = context.Penalties
.Where(p => p.LinkId == linkId ||
p.Link.Children.Any(a => a.IPAddress == ip))
ip.HasValue ? p.Link.Children.Any(a => a.IPAddress == ip) : false)
.Where(p => p.Type == Penalty.PenaltyType.TempBan ||
p.Type == Penalty.PenaltyType.Ban ||
p.Type == Penalty.PenaltyType.Flag)

View File

@ -1,21 +1,18 @@
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using System.Collections.Generic;
using SharedLibraryCore.Objects;
using static SharedLibraryCore.Server;
using System.Reflection;
using System.IO;
using System.Threading.Tasks;
using System.Globalization;
using System.Diagnostics;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using SharedLibraryCore.Database.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static SharedLibraryCore.Server;
namespace SharedLibraryCore
{
@ -28,14 +25,20 @@ namespace SharedLibraryCore
#endif
public static Encoding EncodingType;
public static Localization.Layout CurrentLocalization = new Localization.Layout(new Dictionary<string, string>());
public static EFClient IW4MAdminClient(Server server = null) => new EFClient()
public static EFClient IW4MAdminClient(Server server = null)
{
ClientId = 1,
State = EFClient.ClientState.Connected,
Level = EFClient.Permission.Console,
CurrentServer = server,
Name = "IW4MAdmin"
};
return new EFClient()
{
ClientId = 1,
State = EFClient.ClientState.Connected,
Level = EFClient.Permission.Console,
CurrentServer = server,
CurrentAlias = new EFAlias()
{
Name = "IW4MAdmin"
}
};
}
public static string HttpRequest(string location, string header, string headerValue)
{
@ -64,7 +67,9 @@ namespace SharedLibraryCore
public static String RemoveWords(this string str, int num)
{
if (str == null || str.Length == 0)
{
return "";
}
String newStr = String.Empty;
String[] tmp = str.Split(' ');
@ -72,7 +77,9 @@ namespace SharedLibraryCore
for (int i = 0; i < tmp.Length; i++)
{
if (i >= num)
{
newStr += tmp[i] + ' ';
}
}
return newStr;
@ -105,9 +112,13 @@ namespace SharedLibraryCore
String lookingFor = str.ToLower();
for (EFClient.Permission Perm = EFClient.Permission.User; Perm < EFClient.Permission.Console; Perm++)
{
if (lookingFor.Contains(Perm.ToString().ToLower())
|| lookingFor.Contains(CurrentLocalization.LocalizationIndex[$"GLOBAL_PERMISSION_{Perm.ToString().ToUpper()}"].ToLower()))
{
return Perm;
}
}
return EFClient.Permission.Banned;
}
@ -120,7 +131,10 @@ namespace SharedLibraryCore
public static String StripColors(this string str)
{
if (str == null)
{
return "";
}
str = Regex.Replace(str, @"(\^+((?![a-z]|[A-Z]).){0,1})+", "");
string str2 = Regex.Match(str, @"(^\/+.*$)|(^.*\/+$)")
.Value
@ -161,7 +175,10 @@ namespace SharedLibraryCore
return $"^{colorCode}{localizedLevel ?? level.ToString()}";
}
public static string ToLocalizedLevelName(this EFClient.Permission perm) => CurrentLocalization.LocalizationIndex[$"GLOBAL_PERMISSION_{perm.ToString().ToUpper()}"];
public static string ToLocalizedLevelName(this EFClient.Permission perm)
{
return CurrentLocalization.LocalizationIndex[$"GLOBAL_PERMISSION_{perm.ToString().ToUpper()}"];
}
public static String ProcessMessageToken(this Server server, IList<Helpers.MessageToken> tokens, String str)
{
@ -174,7 +191,9 @@ namespace SharedLibraryCore
var found = tokens.FirstOrDefault(t => t.Name.ToLower() == Identifier.ToLower());
if (found != null)
{
str = str.Replace(Match, found.Process(server));
}
}
return str;
@ -245,11 +264,17 @@ namespace SharedLibraryCore
{
str = str.Substring(0, Math.Min(str.Length, 16));
if (Int64.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long id))
{
return id;
}
var bot = Regex.Match(str, @"bot[0-9]+").Value;
if (!string.IsNullOrEmpty(bot))
{
// should set their GUID to the negation of their 1 based index (-1 - -18)
return -(Convert.ToInt64(bot.Substring(3)) + 1);
}
return long.MinValue;
}
@ -260,9 +285,9 @@ namespace SharedLibraryCore
return ip == null ? int.MaxValue : BitConverter.ToInt32(ip.GetAddressBytes(), 0);
}
public static string ConvertIPtoString(this int ip)
public static string ConvertIPtoString(this int? ip)
{
return new System.Net.IPAddress(BitConverter.GetBytes(ip)).ToString();
return !ip.HasValue ? "" : new System.Net.IPAddress(BitConverter.GetBytes(ip.Value)).ToString();
}
public static String GetTimePassed(DateTime start)
@ -282,19 +307,28 @@ namespace SharedLibraryCore
if (Elapsed.TotalMinutes < 120)
{
if (Elapsed.TotalMinutes < 1.5)
{
return $"1 {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_MINUTES"]}{ago}";
}
return Math.Round(Elapsed.TotalMinutes, 0) + $" {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_MINUTES"]}{ago}";
}
if (Elapsed.TotalHours <= 24)
{
if (Elapsed.TotalHours < 1.5)
{
return $"1 {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_HOURS"]}{ago}";
}
return Math.Round(Elapsed.TotalHours, 0) + $" { CurrentLocalization.LocalizationIndex["GLOBAL_TIME_HOURS"]}{ago}";
}
if (Elapsed.TotalDays <= 90)
{
if (Elapsed.TotalDays < 1.5)
{
return $"1 {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_DAYS"]}{ago}";
}
return Math.Round(Elapsed.TotalDays, 0) + $" {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_DAYS"]}{ago}";
}
if (Elapsed.TotalDays <= 365)
@ -310,19 +344,39 @@ namespace SharedLibraryCore
public static Game GetGame(string gameName)
{
if (gameName.Contains("IW4"))
{
return Game.IW4;
}
if (gameName.Contains("CoD4"))
{
return Game.IW3;
}
if (gameName.Contains("COD_WaW"))
{
return Game.T4;
}
if (gameName.Contains("COD_T5_S"))
{
return Game.T5;
}
if (gameName.Contains("T5M"))
{
return Game.T5M;
}
if (gameName.Contains("IW5"))
{
return Game.IW5;
}
if (gameName.Contains("COD_T6_S"))
{
return Game.T6M;
}
return Game.UKN;
}
@ -337,7 +391,9 @@ namespace SharedLibraryCore
var expressionMatch = Regex.Match(input, @"([0-9]+)(\w+)");
if (!expressionMatch.Success) // fallback to default tempban length of 1 hour
{
return new TimeSpan(1, 0, 0);
}
char lengthDenote = expressionMatch.Groups[2].ToString()[0];
int length = Int32.Parse(expressionMatch.Groups[1].ToString());
@ -377,52 +433,42 @@ namespace SharedLibraryCore
var loc = CurrentLocalization.LocalizationIndex;
if (span.TotalMinutes < 60)
{
return $"{span.Minutes} {loc["GLOBAL_TIME_MINUTES"]}";
}
else if (span.Hours >= 1 && span.TotalHours < 24)
{
return $"{span.Hours} {loc["GLOBAL_TIME_HOURS"]}";
}
else if (span.TotalDays >= 1 && span.TotalDays < 7)
{
return $"{span.Days} {loc["GLOBAL_TIME_DAYS"]}";
}
else if (span.TotalDays >= 7 && span.TotalDays < 90)
{
return $"{Math.Round(span.Days / 7.0, 0)} {loc["GLOBAL_TIME_WEEKS"]}";
}
else if (span.TotalDays >= 90 && span.TotalDays < 365)
{
return $"{Math.Round(span.Days / 30.0, 0)} {loc["GLOBAL_TIME_MONTHS"]}";
}
else if (span.TotalDays >= 365 && span.TotalDays < 36500)
{
return $"{Math.Round(span.Days / 365.0, 0)} {loc["GLOBAL_TIME_YEARS"]}";
}
else if (span.TotalDays >= 36500)
{
return loc["GLOBAL_TIME_FOREVER"];
}
return "unknown";
}
public static EFClient AsEFClient(this Database.Models.EFClient client)
public static bool IsPrivileged(this EFClient p)
{
return client == null ? null : new EFClient()
{
Active = client.Active,
AliasLink = client.AliasLink,
AliasLinkId = client.AliasLinkId,
ClientId = client.ClientId,
ClientNumber = -1,
FirstConnection = client.FirstConnection,
Connections = client.Connections,
NetworkId = client.NetworkId,
TotalConnectionTime = client.TotalConnectionTime,
Masked = client.Masked,
Name = client.CurrentAlias.Name,
IPAddress = client.CurrentAlias.IPAddress,
Level = client.Level,
LastConnection = client.LastConnection == DateTime.MinValue ? DateTime.UtcNow : client.LastConnection,
CurrentAlias = client.CurrentAlias,
CurrentAliasId = client.CurrentAlias.AliasId,
// todo: make sure this is up to date
IsBot = client.IPAddress == int.MinValue,
Password = client.Password,
PasswordSalt = client.PasswordSalt
};
return p.Level > EFClient.Permission.User;
}
public static bool IsPrivileged(this EFClient p) => p.Level > EFClient.Permission.User;
public static bool PromptBool(string question)
{
Console.Write($"{question}? [y/n]: ");
@ -474,7 +520,9 @@ namespace SharedLibraryCore
int.TryParse(lineSplit[cIDPos].Trim(), out pID);
if (pID == -1) // special case similar to mod_suicide
{
int.TryParse(lineSplit[2], out pID);
}
return pID;
}
@ -489,7 +537,9 @@ namespace SharedLibraryCore
{
dict = new Dictionary<string, string>();
for (int i = 0; i < values.Length; i += 2)
{
dict.Add(values[i], values[i + 1]);
}
}
return dict;
@ -518,15 +568,30 @@ namespace SharedLibraryCore
return cmdLine.Length > 1 ? cmdLine[1] : cmdLine[0];
}
public static string ToBase64UrlSafeString(this string src) => Convert.ToBase64String(src.Select(c => Convert.ToByte(c)).ToArray()).Replace('+', '-').Replace('/', '_');
public static string ToBase64UrlSafeString(this string src)
{
return Convert.ToBase64String(src.Select(c => Convert.ToByte(c)).ToArray()).Replace('+', '-').Replace('/', '_');
}
public static Task<Dvar<T>> GetDvarAsync<T>(this Server server, string dvarName) => server.RconParser.GetDvarAsync<T>(server.RemoteConnection, dvarName);
public static Task<Dvar<T>> GetDvarAsync<T>(this Server server, string dvarName)
{
return server.RconParser.GetDvarAsync<T>(server.RemoteConnection, dvarName);
}
public static Task SetDvarAsync(this Server server, string dvarName, object dvarValue) => server.RconParser.SetDvarAsync(server.RemoteConnection, dvarName, dvarValue);
public static Task SetDvarAsync(this Server server, string dvarName, object dvarValue)
{
return server.RconParser.SetDvarAsync(server.RemoteConnection, dvarName, dvarValue);
}
public static async Task<string[]> ExecuteCommandAsync(this Server server, string commandName) => await server.RconParser.ExecuteCommandAsync(server.RemoteConnection, commandName);
public static async Task<string[]> ExecuteCommandAsync(this Server server, string commandName)
{
return await server.RconParser.ExecuteCommandAsync(server.RemoteConnection, commandName);
}
public static Task<List<EFClient>> GetStatusAsync(this Server server) => server.RconParser.GetStatusAsync(server.RemoteConnection);
public static Task<List<EFClient>> GetStatusAsync(this Server server)
{
return server.RconParser.GetStatusAsync(server.RemoteConnection);
}
public static async Task<Dictionary<string, string>> GetInfoAsync(this Server server)
{
@ -535,7 +600,10 @@ namespace SharedLibraryCore
{
response = await server.RemoteConnection.SendQueryAsync(RCon.StaticHelpers.QueryType.GET_INFO);
if (response.Length == 2)
{
break;
}
await Task.Delay(RCon.StaticHelpers.FloodProtectionInterval);
}
return response.FirstOrDefault(r => r[0] == '\\')?.DictionaryFromKeyValue();
@ -548,7 +616,10 @@ namespace SharedLibraryCore
return double.Parse(version) / 1000.0;
}
public static string GetVersionAsString() => Assembly.GetCallingAssembly().GetName().Version.ToString();
public static string GetVersionAsString()
{
return Assembly.GetCallingAssembly().GetName().Version.ToString();
}
#if DEBUG == true