Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server refactor #403

Merged
merged 29 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c8654a6
Turn world manager into a BackgroundService
Tides Nov 16, 2023
2e6da36
Abstractions refactor pt.1
Tides Nov 16, 2023
a67ea67
Update Region.cs
Tides Nov 16, 2023
7d3b61d
Abstractions refactor pt.2
Tides Nov 16, 2023
2393b34
Move world generator registering to WorldManager
Tides Nov 16, 2023
7307ac8
abstractions pt.3
Tides Nov 16, 2023
e13bd36
Use packet broadcaster
Tides Nov 16, 2023
da4ad73
Fix event parameters
Tides Nov 16, 2023
5aaa36a
Simplify ConsoleApp.Program.cs
Tides Nov 16, 2023
922f002
Refactor Living.cs
Tides Nov 16, 2023
cafb7a6
A little cleanup
Tides Nov 16, 2023
9c699fd
WE START WOOOOO
Tides Nov 16, 2023
6fcfd3d
Update Player.cs
Tides Nov 16, 2023
737f4cd
oop
Tides Nov 16, 2023
22b2783
Merge branch 'master' into server-refactor
Tides Nov 16, 2023
aa6ede6
Fix up some NREs and wait for worlds to be ready
Tides Nov 17, 2023
0663c3a
Region loading does not need to be blocked
Tides Nov 17, 2023
93dde3d
Add a direct send method that won't get processed through the queue
Tides Nov 17, 2023
6dae353
Just use JsonNamingPolicy.SnakeCaseLower :))
Tides Nov 18, 2023
cd68c5e
world gen status
Jonpro03 Nov 18, 2023
2908dc6
Fix strange chunk unloading bug
Jonpro03 Nov 18, 2023
a8695d6
Forgot to save O_O
Jonpro03 Nov 18, 2023
c7c7013
Update OperatorList & IOperatorList
Tides Nov 20, 2023
5c112ad
Last bit refactor
Tides Nov 20, 2023
4ab15e6
Make user cache a service instead
Tides Nov 20, 2023
f26c8ce
Add sealed modifier to most classes (final commit)
Tides Nov 20, 2023
8bfc979
OKAY ACTUAL FINAL COMMIT
Tides Nov 20, 2023
6c8f026
Fix bug loading worlds from disk
Jonpro03 Nov 21, 2023
bc6599d
Document the non self explanatory properties in config
Tides Nov 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Obsidian.API/Events/ContainerClickEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public sealed class ContainerClickEventArgs : ContainerEventArgs, ICancellable
public bool IsCancelled { get; private set; }

[SetsRequiredMembers]
internal ContainerClickEventArgs(IPlayer player, BaseContainer container, ItemStack item) : base(player)
internal ContainerClickEventArgs(IPlayer player, IServer server, BaseContainer container, ItemStack item) : base(player, server)
{
this.Container = container;
this.Item = item;
Expand Down
2 changes: 1 addition & 1 deletion Obsidian.API/Events/ContainerClosedEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ public sealed class ContainerClosedEventArgs : ContainerEventArgs, ICancellable
{
public bool IsCancelled { get; private set; }

internal ContainerClosedEventArgs(IPlayer player) : base(player)
internal ContainerClosedEventArgs(IPlayer player, IServer server) : base(player, server)
{
}

Expand Down
6 changes: 2 additions & 4 deletions Obsidian.API/Events/ContainerEventArgs.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using System.Diagnostics.CodeAnalysis;

namespace Obsidian.API.Events;
namespace Obsidian.API.Events;

public class ContainerEventArgs : PlayerEventArgs
{
public required BaseContainer Container { get; init; }

protected ContainerEventArgs(IPlayer player) : base(player)
protected ContainerEventArgs(IPlayer player, IServer server) : base(player, server)
{
}
}
3 changes: 2 additions & 1 deletion Obsidian.API/Events/IncomingChatMessageEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public class IncomingChatMessageEventArgs : PlayerEventArgs, ICancellable
/// <param name="player">The player which sent the message.</param>
/// <param name="message">The message which was sent.</param>
/// <param name="format">Any formatting appied to the message.</param>
public IncomingChatMessageEventArgs(IPlayer player, string message, string format) : base(player)
/// <param name="server">The server this took place in.</param>
public IncomingChatMessageEventArgs(IPlayer player, IServer server, string message, string format) : base(player, server)
{
this.Message = message;
this.Format = format;
Expand Down
3 changes: 2 additions & 1 deletion Obsidian.API/Events/PacketReceivedEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public sealed class PacketReceivedEventArgs : PlayerEventArgs, ICancellable
/// <param name="player">The player involved in this event.</param>
/// <param name="id">Id of the received packet.</param>
/// <param name="data">Packet data, excluding packet id and packet length.</param>
public PacketReceivedEventArgs(IPlayer player, int id, ReadOnlyMemory<byte> data) : base(player)
/// <param name="server">The server this took place in.</param>
public PacketReceivedEventArgs(IPlayer player, IServer server, int id, ReadOnlyMemory<byte> data) : base(player, server)
{
Id = id;
Data = data;
Expand Down
2 changes: 1 addition & 1 deletion Obsidian.API/Events/PermissionGrantedEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public class PermissionGrantedEventArgs : PlayerEventArgs
{
public string Permission { get; }

public PermissionGrantedEventArgs(IPlayer player, string permission) : base(player)
public PermissionGrantedEventArgs(IPlayer player, IServer server, string permission) : base(player, server)
{
Permission = permission;
}
Expand Down
2 changes: 1 addition & 1 deletion Obsidian.API/Events/PermissionRevokedEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public class PermissionRevokedEventArgs : PlayerEventArgs
{
public string Permission { get; }

public PermissionRevokedEventArgs(IPlayer player, string permission) : base(player)
public PermissionRevokedEventArgs(IPlayer player, IServer server, string permission) : base(player, server)
{
Permission = permission;
}
Expand Down
2 changes: 1 addition & 1 deletion Obsidian.API/Events/PlayerEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class PlayerEventArgs : BaseMinecraftEventArgs
/// </summary>
public IPlayer Player { get; }

protected PlayerEventArgs(IPlayer player) : base(player.Server)
protected PlayerEventArgs(IPlayer player, IServer server) : base(server)
{
Player = player;
}
Expand Down
2 changes: 1 addition & 1 deletion Obsidian.API/Events/PlayerInteractEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public sealed class PlayerInteractEventArgs : PlayerEventArgs, ICancellable
/// <inheritdoc />
public bool IsCancelled { get; private set; }

public PlayerInteractEventArgs(IPlayer player) : base(player) { }
public PlayerInteractEventArgs(IPlayer player, IServer server) : base(player, server) { }

/// <inheritdoc />
public void Cancel()
Expand Down
2 changes: 1 addition & 1 deletion Obsidian.API/Events/PlayerJoinEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class PlayerJoinEventArgs : PlayerEventArgs
/// </summary>
public DateTimeOffset JoinDate { get; }

public PlayerJoinEventArgs(IPlayer player, DateTimeOffset join) : base(player)
public PlayerJoinEventArgs(IPlayer player, IServer server, DateTimeOffset join) : base(player, server)
{
this.JoinDate = join;
}
Expand Down
2 changes: 1 addition & 1 deletion Obsidian.API/Events/PlayerLeaveEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class PlayerLeaveEventArgs : PlayerEventArgs
/// </summary>
public DateTimeOffset LeaveDate { get; }

public PlayerLeaveEventArgs(IPlayer player, DateTimeOffset leave) : base(player)
public PlayerLeaveEventArgs(IPlayer player, IServer server, DateTimeOffset leave) : base(player, server)
{
this.LeaveDate = leave;
}
Expand Down
2 changes: 1 addition & 1 deletion Obsidian.API/Events/PlayerTeleportEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public class PlayerTeleportEventArgs : PlayerEventArgs
public VectorF OldPosition { get; }
public VectorF NewPosition { get; }

public PlayerTeleportEventArgs(IPlayer player, VectorF oldPosition, VectorF newPosition) : base(player)
public PlayerTeleportEventArgs(IPlayer player, IServer server, VectorF oldPosition, VectorF newPosition) : base(player, server)
{
OldPosition = oldPosition;
NewPosition = newPosition;
Expand Down
2 changes: 1 addition & 1 deletion Obsidian.API/Logging/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,5 @@ void PrintLinePrefix()

public bool IsEnabled(LogLevel logLevel) => logLevel >= MinimumLevel;

public IDisposable BeginScope<TState>(TState state) => throw new NotImplementedException();
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
}
30 changes: 14 additions & 16 deletions Obsidian.API/Utilities/Extensions.StringManipulation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.RegularExpressions;

namespace Obsidian.API.Utilities;

public static partial class Extensions
{
public static readonly Regex pattern = new(@"[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+");

/// <remarks>
/// This method is not and shouldn't be used in performance-critical sections.
/// Source: https://stackoverflow.com/a/1415187
Expand Down Expand Up @@ -38,7 +37,6 @@ public static string ToPascalCase(this string snakeCase)
// Alternative implementation:
// var textInfo = System.Globalization.CultureInfo.CurrentCulture.TextInfo;
// return string.Join("", snakeCase.Split('_').Select(s => textInfo.ToTitleCase(s)));

int spaceCount = 0;
for (int i = 0; i < snakeCase.Length; i++)
{
Expand Down Expand Up @@ -94,7 +92,7 @@ public static string Capitalize(this string value)

public static bool EqualsIgnoreCase(this string a, string b) => a.Equals(b, StringComparison.OrdinalIgnoreCase);

public static string ToSnakeCase(this string str) => string.Join("_", pattern.Matches(str)).ToLower();
public static string ToSnakeCase(this string str) => JsonNamingPolicy.SnakeCaseLower.ConvertName(str);

/// <summary>
/// Trims resource tag from the start and removes '_' characters.
Expand Down Expand Up @@ -132,7 +130,7 @@ public static string TrimResourceTag(this string value, bool keepUnderscores = f
});
}

[Obsolete("Do not use. Kept as a masterpiece.")]
//[Obsolete("Do not use. Kept as a masterpiece.")]
// This method is an absolute masterpiece. Its author must've entered
// the highest plane of existance when writing it. The purpose of this
// method is to make a string camelCase, but at all places where it was
Expand All @@ -153,15 +151,15 @@ public static string TrimResourceTag(this string value, bool keepUnderscores = f
// The text appears 8 times in memory, in different forms (including the
// returned string). That means that every call produces around 7 * str.Length
// * sizeof(char) bytes of garbage.
public static string ToCamelCase(this string str)
{
return new string(
new CultureInfo("en-US", false)
.TextInfo
.ToTitleCase(string.Join(" ", pattern.Matches(str)).ToLower())
.Replace(@" ", "")
.Select((x, i) => i == 0 ? char.ToLower(x) : x)
.ToArray()
);
}
//public static string ToCamelCase(this string str)
//{
// return new string(
// new CultureInfo("en-US", false)
// .TextInfo
// .ToTitleCase(string.Join(" ", pattern.Matches(str)).ToLower())
// .Replace(@" ", "")
// .Select((x, i) => i == 0 ? char.ToLower(x) : x)
// .ToArray()
// );
//}
}
2 changes: 0 additions & 2 deletions Obsidian.API/_Interfaces/IEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ namespace Obsidian.API;

public interface IEntity
{
public IServer Server { get; }

public IWorld World { get; }
public INavigator? Navigator { get; set; }

Expand Down
6 changes: 3 additions & 3 deletions Obsidian.API/_Interfaces/ILiving.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public interface ILiving : IEntity
/// <summary>
/// Clears all potion effects of the entity.
/// </summary>
public Task ClearPotionEffects();
public void ClearPotionEffects();

/// <summary>
/// Adds the given <see cref="PotionEffect"/> to the entity.
Expand All @@ -43,12 +43,12 @@ public interface ILiving : IEntity
/// <param name="showParticles">Whether to show the particles or not.</param>
/// <param name="showIcon">Whether to show the icon on the client or not.</param>
/// <param name="isAmbient">Whether the potion is emitted by ambient source e.g. the beacon. The icon has a blue border in the HUD if its ambient.</param>
public Task AddPotionEffectAsync(PotionEffect potion, int duration, byte amplifier = 0, bool showParticles = true,
public void AddPotionEffect(PotionEffect potion, int duration, byte amplifier = 0, bool showParticles = true,
bool showIcon = true, bool isAmbient = false);

/// <summary>
/// Removes the given <see cref="PotionEffect"/> from the entity.
/// </summary>
/// <param name="potion">The potion effect to be removed.</param>
public Task RemovePotionEffectAsync(PotionEffect potion);
public void RemovePotionEffect(PotionEffect potion);
}
6 changes: 2 additions & 4 deletions Obsidian.API/_Interfaces/IOperatorList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ namespace Obsidian.API;

public interface IOperatorList
{
public void AddOperator(IPlayer player);
public void AddOperator(IPlayer player, int level = 4, bool bypassesPlayerLimit = false);
public bool CreateRequest(IPlayer player);
public bool ProcessRequest(IPlayer player, string? code);
public void AddOperator(string username);
public bool ProcessRequest(IPlayer player, string code);
public void RemoveOperator(IPlayer player);
public void RemoveOperator(string username);
public bool IsOperator(IPlayer p);
public ImmutableList<IPlayer> GetOnlineOperators();
}
10 changes: 10 additions & 0 deletions Obsidian.API/_Interfaces/IRegion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Obsidian.API;
public interface IRegion : IAsyncDisposable
{
public int X { get; }
public int Z { get; }

public int LoadedChunkCount { get; }

public string RegionFolder { get; }
}
2 changes: 2 additions & 0 deletions Obsidian.API/_Interfaces/IServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public interface IServer

public IScoreboardManager ScoreboardManager { get; }

public Task RunAsync();

public bool IsPlayerOnline(string username);
public bool IsPlayerOnline(Guid uuid);
public void BroadcastMessage(string message);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
using Obsidian.API._Types.Config;
using Obsidian.API.Config;

namespace Obsidian.API;

public interface IServerConfiguration
{
public bool? Baah { get; set; }
public bool CanThrottle => this.ConnectionThrottle > 0;
public bool UDPBroadcast { get; set; }
public bool IpWhitelistEnabled { get; set; }

public long ConnectionThrottle { get; set; }

/// <summary>
/// Server description.
/// </summary>
Expand Down Expand Up @@ -33,9 +40,13 @@ public interface IServerConfiguration
/// Maximum amount of players that is allowed to be connected at the same time.
/// </summary>
public int MaxPlayers { get; set; }
public int PregenerateChunkRange { get; set; }
public int TimeTickSpeedMultiplier { get; set; }
Tides marked this conversation as resolved.
Show resolved Hide resolved

public bool AllowOperatorRequests { get; set; }

public bool WhitelistEnabled { get; set; }

/// <summary>
/// Whether each login/client gets a random username where multiple connections from the same host will be allowed.
/// </summary>
Expand Down Expand Up @@ -73,8 +84,13 @@ public interface IServerConfiguration
/// <remarks>See more at https://wiki.vg/RCON</remarks>
public bool EnableRcon => Rcon is not null;

public bool VerboseExceptionLogging { get; set; }

/// <summary>
/// Remote Console configuration
/// </summary>
public RconConfig? Rcon { get; set; }

public List<string> WhitelistedIPs { get; set; }
public List<WhitelistedPlayer> Whitelisted { get; set; }
}
15 changes: 13 additions & 2 deletions Obsidian.API/_Interfaces/IWorld.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections.Concurrent;

namespace Obsidian.API;

public interface IWorld
public interface IWorld : IAsyncDisposable
{
public string Name { get; }

Expand All @@ -14,6 +16,12 @@ public interface IWorld

public Gamemode DefaultGamemode { get; }

public int RegionCount { get; }
public int LoadedChunkCount { get; }
public int ChunksToGenCount { get; }

public int GetTotalLoadedEntities();

public Task<IBlock?> GetBlockAsync(Vector location);
public Task<IBlock?> GetBlockAsync(int x, int y, int z);
public Task SetBlockAsync(Vector location, IBlock block);
Expand All @@ -26,5 +34,8 @@ public interface IWorld
public Task<int?> GetWorldSurfaceHeightAsync(int x, int z);

public Task<IEntity> SpawnEntityAsync(VectorF position, EntityType type);
public Task SpawnExperienceOrbs(VectorF position, short count);
public void SpawnExperienceOrbs(VectorF position, short count);

public Task DoWorldTickAsync();
public Task FlushRegionsAsync();
}
25 changes: 25 additions & 0 deletions Obsidian.API/_Interfaces/IWorldManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Diagnostics.CodeAnalysis;

namespace Obsidian.API;
public interface IWorldManager : IAsyncDisposable
{
public bool ReadyToJoin { get; }

public Dictionary<string, Type> WorldGenerators { get; }

public int GeneratingChunkCount { get; }
public int LoadedChunkCount { get; }

public int RegionCount { get; }

public IWorld DefaultWorld { get; }

public IReadOnlyCollection<IWorld> GetAvailableWorlds();

public Task FlushLoadedWorldsAsync();

public Task TickWorldsAsync();

public bool TryGetWorld(string name, [NotNullWhen(true)] out IWorld? world);
public bool TryGetWorld<TWorld>(string name, [NotNullWhen(true)] out TWorld? world) where TWorld : IWorld;
}
2 changes: 1 addition & 1 deletion Obsidian.API/_Types/Config/RconConfig.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Obsidian.API._Types.Config;
namespace Obsidian.API.Config;

public class RconConfig
{
Expand Down
6 changes: 6 additions & 0 deletions Obsidian.API/_Types/WhitelistedPlayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Obsidian.API;
public readonly struct WhitelistedPlayer
{
public required string Name { get; init; }
public required Guid Id { get; init; }
}
Loading
Loading