# Conflicts: # .github/CODEOWNERS # .github/PULL_REQUEST_TEMPLATE.md # Content.Client/Changelog/ChangelogTab.xaml.cs # Content.Client/Chemistry/UI/ChemMasterWindow.xaml # Content.Client/Entry/EntryPoint.cs # Content.Client/GameTicking/Managers/ClientGameTicker.cs # Content.Client/Launcher/LauncherConnectingGui.xaml # Content.Client/Lobby/LobbyState.cs # Content.Client/Lobby/UI/LobbyGui.xaml # Content.Client/Paper/UI/PaperWindow.xaml.cs # Content.Client/StationRecords/GeneralStationRecordConsoleWindow.xaml.cs # Content.Client/Stylesheets/StyleNano.cs # Content.Client/UserInterface/Screens/SeparatedChatGameScreen.xaml # Content.Client/UserInterface/Systems/Ghost/Widgets/GhostGui.xaml.cs # Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml # Content.IntegrationTests/Tests/Destructible/DestructibleDamageGroupTest.cs # Content.IntegrationTests/Tests/PostMapInitTest.cs # Content.IntegrationTests/Tests/Power/StationPowerTests.cs # Content.Packaging/ServerPackaging.cs # Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs # Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs # Content.Server/Atmos/TileAtmosphere.cs # Content.Server/Bible/BibleSystem.cs # Content.Server/Chat/Systems/ChatSystem.cs # Content.Server/Content.Server.csproj # Content.Server/Discord/DiscordLink/DiscordLink.cs # Content.Server/GameTicking/GameTicker.LobbyBackground.cs # Content.Server/GameTicking/GameTicker.Spawning.cs # Content.Server/Ghost/GhostSystem.cs # Content.Server/Kitchen/Components/MicrowaveComponent.cs # Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs # Content.Server/Mech/Systems/MechSystem.cs # Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs # Content.Server/Medical/DefibrillatorSystem.cs # Content.Server/Medical/HealthAnalyzerSystem.cs # Content.Server/Radio/EntitySystems/HeadsetSystem.cs # Content.Server/Remotes/DoorRemoteSystem.cs # Content.Server/RoundEnd/RoundEndSystem.cs # Content.Server/Shuttles/Systems/DockingSystem.Shuttle.cs # Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs # Content.Server/Tips/TipsSystem.cs # Content.Server/Traitor/Uplink/UplinkSystem.cs # Content.Server/Weapons/Ranged/Systems/GunSystem.cs # Content.Server/Zombies/ZombieSystem.Transform.cs # Content.Server/Zombies/ZombieSystem.cs # Content.Shared/Bed/BedSystem.cs # Content.Shared/Blocking/BlockingSystem.User.cs # Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs # Content.Shared/Chat/SharedSuicideSystem.cs # Content.Shared/Chemistry/Components/HyposprayComponent.cs # Content.Shared/Chemistry/EntitySystems/HypospraySystem.cs # Content.Shared/Chemistry/EntitySystems/ScoopableSolutionSystem.cs # Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs # Content.Shared/Chemistry/Events/HyposprayEvents.cs # Content.Shared/Content.Shared.csproj # Content.Shared/Damage/Systems/DamageableSystem.cs # Content.Shared/Friction/TileFrictionController.cs # Content.Shared/GameTicking/SharedGameTicker.cs # Content.Shared/Interaction/InteractHand.cs # Content.Shared/Lock/LockSystem.cs # Content.Shared/Medical/Healing/HealingSystem.cs # Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs # Content.Shared/Nutrition/EntitySystems/HungerSystem.cs # Content.Shared/Silicons/StationAi/SharedStationAiSystem.Airlock.cs # Content.Shared/Throwing/ThrowingSystem.cs # Content.Shared/Trigger/Systems/TriggerOnHitscanSystem.cs # Content.Shared/Weapons/Hitscan/Systems/HitscanBasicDamageSystem.cs # Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs # Content.Shared/Weapons/Ranged/Components/BatteryWeaponFireModesComponent.cs # Content.Shared/Weapons/Ranged/Components/HitscanBatteryAmmoProviderComponent.cs # Content.Shared/Weapons/Ranged/Systems/BatteryWeaponFireModesSystem.cs # Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs # Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Battery.cs # Content.Shared/Zombies/ZombieComponent.cs # Content.Shared/_Sunrise/Lobby/LobbyBackgroundPrototype.cs # README.md # Resources/Locale/en-US/_strings/borg/borg.ftl # Resources/Locale/en-US/_strings/chemistry/components/hypospray-component.ftl # Resources/Locale/en-US/_strings/chemistry/components/injector-component.ftl # Resources/Locale/en-US/_strings/commands/pauseatmos-command.ftl # Resources/Locale/en-US/_strings/commands/quick-inspect-command.ftl # Resources/Locale/en-US/_strings/commands/show-wallmounts-command.ftl # Resources/Locale/en-US/_strings/commands/substepatmos-command.ftl # Resources/Locale/en-US/_strings/fluids/components/equip-spray-component.ftl # Resources/Locale/en-US/_strings/game-ticking/game-presets/preset-revolutionary.ftl # Resources/Locale/en-US/_strings/job/job-names.ftl # Resources/Locale/en-US/_strings/lobby/lobby-state-background.ftl # Resources/Locale/en-US/_strings/reagents/meta/medicine.ftl # Resources/Locale/en-US/_strings/reagents/meta/physical-desc.ftl # Resources/Locale/en-US/_strings/silicons/borg-module.ftl # Resources/Locale/en-US/_strings/store/changeling-catalog.ftl # Resources/Locale/en-US/_strings/store/currency.ftl # Resources/Locale/en-US/_strings/store/store.ftl # Resources/Locale/en-US/_strings/store/uplink-catalog.ftl # Resources/Prototypes/Body/Organs/slime.yml # Resources/Prototypes/Catalog/Fills/Backpacks/backpack.yml # Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml # Resources/Prototypes/Catalog/Fills/Boxes/ammunition.yml # Resources/Prototypes/Catalog/Fills/Boxes/emergency.yml # Resources/Prototypes/Catalog/Fills/Crates/antag.yml # Resources/Prototypes/Catalog/Fills/Crates/armory.yml # Resources/Prototypes/Catalog/Fills/Crates/botany.yml # Resources/Prototypes/Catalog/Fills/Crates/fun.yml # Resources/Prototypes/Catalog/Fills/Crates/medical.yml # Resources/Prototypes/Catalog/Fills/Crates/salvage.yml # Resources/Prototypes/Catalog/Fills/Crates/security.yml # Resources/Prototypes/Catalog/Fills/Crates/service.yml # Resources/Prototypes/Catalog/Fills/Crates/syndicate.yml # Resources/Prototypes/Catalog/Fills/Items/belt.yml # Resources/Prototypes/Catalog/Fills/Items/briefcases.yml # Resources/Prototypes/Catalog/Fills/Items/firstaidkits.yml # Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml # Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml # Resources/Prototypes/Catalog/Fills/Lockers/heads.yml # Resources/Prototypes/Catalog/Fills/Lockers/security.yml # Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml # Resources/Prototypes/Catalog/uplink_catalog.yml # Resources/Prototypes/Entities/Clothing/Back/backpacks.yml # Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml # Resources/Prototypes/Entities/Debugging/debug_sweps.yml # Resources/Prototypes/Entities/Debugging/stress_test.yml # Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml # Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml # Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml # Resources/Prototypes/Entities/Mobs/Cyborgs/xenoborgs.yml # Resources/Prototypes/Entities/Mobs/NPCs/animals.yml # Resources/Prototypes/Entities/Mobs/NPCs/carp.yml # Resources/Prototypes/Entities/Objects/Devices/base_handheld.yml # Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_misc.yml # Resources/Prototypes/Entities/Objects/Fun/dice_bag.yml # Resources/Prototypes/Entities/Objects/Fun/snap_pops.yml # Resources/Prototypes/Entities/Objects/Materials/Sheets/other.yml # Resources/Prototypes/Entities/Objects/Materials/parts.yml # Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml # Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml # Resources/Prototypes/Entities/Objects/Shields/shields.yml # Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml # Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml # Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml # Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml # Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml # Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml # Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml # Resources/Prototypes/Entities/Objects/Tools/glowstick.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/antimateriel.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/magnum.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/heavy_rifle.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/light_rifle.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/magnum.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/pistol.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/rifle.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/shotgun.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/light_rifle.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/magnum.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/pistol.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/rifle.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/magnum.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/pistol.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/rifle_light.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/explosives.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Pistols/pistols.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/hitscan.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml # Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml # Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml # Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml # Resources/Prototypes/Entities/Structures/Furniture/dresser.yml # Resources/Prototypes/Entities/Structures/Machines/lathe.yml # Resources/Prototypes/Entities/Structures/Shuttles/cannons.yml # Resources/Prototypes/Entities/Structures/Walls/walls.yml # Resources/Prototypes/GameRules/roundstart.yml # Resources/Prototypes/GameRules/unknown_shuttles.yml # Resources/Prototypes/InventoryTemplates/aghost_inventory_template.yml # Resources/Prototypes/Loadouts/Jobs/Security/security_officer.yml # Resources/Prototypes/Loadouts/loadout_groups.yml # Resources/Prototypes/Loadouts/role_loadouts.yml # Resources/Prototypes/Maps/Pools/default.yml # Resources/Prototypes/Maps/amber.yml # Resources/Prototypes/Maps/oasis.yml # Resources/Prototypes/Maps/reach.yml # Resources/Prototypes/Objectives/objectiveGroups.yml # Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml # Resources/Prototypes/Reagents/medicine.yml # Resources/Prototypes/Reagents/narcotics.yml # Resources/Prototypes/Reagents/toxins.yml # Resources/Prototypes/Recipes/Reactions/medicine.yml # Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml # Resources/Prototypes/Roles/Jobs/Security/security_cadet.yml # Resources/Prototypes/Roles/Jobs/Security/security_officer.yml # Resources/Prototypes/Roles/Jobs/Security/warden.yml # Resources/Prototypes/Roles/Jobs/Wildcards/zookeeper.yml # Resources/Prototypes/Roles/play_time_trackers.yml # Resources/Prototypes/Shuttles/shuttle_incoming_event.yml # Resources/Prototypes/Species/species_weights.yml # Resources/Prototypes/Store/presets.yml # Resources/Prototypes/ai_factions.yml # Resources/Prototypes/borg_types.yml # Resources/Prototypes/explosion.yml # Resources/Prototypes/game_presets.yml # Resources/Prototypes/lobbyscreens.yml # Resources/Prototypes/silicon-laws.yml # Resources/Textures/Clothing/Back/Duffels/syndicate.rsi/icon-med.png # Resources/Textures/Clothing/Back/Duffels/syndicate.rsi/meta.json # Resources/Textures/Objects/Specific/Mech/mecha.rsi/meta.json # Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-broken.png # Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-empty.png # Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley-open.png # Resources/Textures/Objects/Specific/Mech/mecha.rsi/ripley.png # Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_chassis.png # Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_harness+o.png # Resources/Textures/Objects/Specific/Mech/ripley_construction.rsi/ripley_harness.png # Resources/Textures/Objects/Specific/Medical/hypospray.rsi/meta.json # Resources/Textures/Objects/Specific/Medical/medical.rsi/meta.json # Resources/Textures/Objects/Weapons/Guns/Projectiles/projectiles.rsi/meta.json # Resources/Textures/Objects/Weapons/Guns/Projectiles/projectiles2.rsi/meta.json # Resources/Textures/Structures/Storage/canister.rsi/meta.json # Resources/Textures/Structures/Storage/tanks.rsi/meta.json # Resources/migration.yml # RobustToolbox # SECURITY.md # SpaceStation14.sln
260 lines
8.9 KiB
C#
260 lines
8.9 KiB
C#
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Content.Shared.CCVar;
|
|
using Robust.Shared;
|
|
using Robust.Shared.Configuration;
|
|
using Robust.Shared.ContentPack;
|
|
using Robust.Shared.Serialization.Manager;
|
|
using Robust.Shared.Serialization.Markdown;
|
|
using Robust.Shared.Serialization.Markdown.Mapping;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Client.Changelog
|
|
{
|
|
public sealed partial class ChangelogManager : IPostInjectInit
|
|
{
|
|
[Dependency] private readonly ILogManager _logManager = default!;
|
|
[Dependency] private readonly IResourceManager _resource = default!;
|
|
[Dependency] private readonly ISerializationManager _serialization = default!;
|
|
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
|
|
|
private const string SawmillName = "changelog";
|
|
public const string MainChangelogName = "Changelog";
|
|
|
|
private ISawmill _sawmill = default!;
|
|
|
|
public bool NewChangelogEntries { get; private set; }
|
|
public int LastReadId { get; private set; }
|
|
public int MaxId { get; private set; }
|
|
|
|
public event Action? NewChangelogEntriesChanged;
|
|
|
|
/// <summary>
|
|
/// Ran when the user opens ("read") the changelog,
|
|
/// stores the new ID to disk and clears <see cref="NewChangelogEntries"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <see cref="LastReadId"/> is NOT cleared
|
|
/// since that's used in the changelog menu to show the "since you last read" bar.
|
|
/// </remarks>
|
|
public void SaveNewReadId()
|
|
{
|
|
NewChangelogEntries = false;
|
|
NewChangelogEntriesChanged?.Invoke();
|
|
|
|
using var sw = _resource.UserData.OpenWriteText(new ($"/changelog_last_seen_{_configManager.GetCVar(CCVars.ServerId)}"));
|
|
|
|
sw.Write(MaxId.ToString());
|
|
}
|
|
|
|
public async void Initialize()
|
|
{
|
|
// Open changelog purely to compare to the last viewed date.
|
|
var changelogs = await LoadChangelog();
|
|
UpdateChangelogs(changelogs);
|
|
_configManager.OnValueChanged(CCVars.ServerId, OnServerIdCVarChanged);
|
|
}
|
|
|
|
private void UpdateChangelogs(List<Changelog> changelogs)
|
|
{
|
|
if (changelogs.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var mainChangelogs = changelogs.Where(c => c.Name == MainChangelogName).ToArray();
|
|
if (mainChangelogs.Length == 0)
|
|
{
|
|
_sawmill.Error($"No changelog file found in Resources/Changelog with name {MainChangelogName}");
|
|
return;
|
|
}
|
|
|
|
var changelog = changelogs[0];
|
|
if (mainChangelogs.Length > 1)
|
|
{
|
|
_sawmill.Error($"More than one file found in Resource/Changelog with name {MainChangelogName}");
|
|
}
|
|
|
|
if (changelog.Entries.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
MaxId = changelog.Entries.Max(c => c.Id);
|
|
|
|
CheckLastSeenEntry();
|
|
}
|
|
|
|
private void CheckLastSeenEntry()
|
|
{
|
|
var path = new ResPath($"/changelog_last_seen_{_configManager.GetCVar(CCVars.ServerId)}");
|
|
if (_resource.UserData.TryReadAllText(path, out var lastReadIdText))
|
|
{
|
|
LastReadId = int.Parse(lastReadIdText);
|
|
}
|
|
|
|
NewChangelogEntries = LastReadId < MaxId;
|
|
|
|
NewChangelogEntriesChanged?.Invoke();
|
|
}
|
|
|
|
private void OnServerIdCVarChanged(string newValue)
|
|
{
|
|
CheckLastSeenEntry();
|
|
}
|
|
|
|
public Task<List<Changelog>> LoadChangelog()
|
|
{
|
|
return Task.Run(() =>
|
|
{
|
|
var changelogs = new List<Changelog>();
|
|
var directory = new ResPath("/Changelog");
|
|
foreach (var file in _resource.ContentFindFiles(new ResPath("/Changelog/")))
|
|
{
|
|
if (file.Directory != directory || file.Extension != "yml")
|
|
continue;
|
|
|
|
var yamlData = _resource.ContentFileReadYaml(file);
|
|
|
|
if (yamlData.Documents.Count == 0)
|
|
continue;
|
|
|
|
var node = yamlData.Documents[0].RootNode.ToDataNodeCast<MappingDataNode>();
|
|
var changelog = _serialization.Read<Changelog>(node, notNullableOverride: true);
|
|
if (string.IsNullOrWhiteSpace(changelog.Name))
|
|
changelog.Name = file.FilenameWithoutExtension;
|
|
|
|
changelogs.Add(changelog);
|
|
}
|
|
|
|
changelogs.Sort((a, b) => a.Order.CompareTo(b.Order));
|
|
return changelogs;
|
|
});
|
|
}
|
|
|
|
// Sunrise-Start
|
|
public Changelog MergeChangelogs(List<Changelog> changelogs)
|
|
{
|
|
var combinedChangelog = new Changelog();
|
|
|
|
foreach (var changelog in changelogs)
|
|
{
|
|
combinedChangelog.Entries.AddRange(changelog.Entries);
|
|
|
|
if (!string.IsNullOrEmpty(changelog.Name))
|
|
{
|
|
combinedChangelog.Name = changelog.Name;
|
|
}
|
|
|
|
if (changelog.AdminOnly)
|
|
{
|
|
combinedChangelog.AdminOnly = true;
|
|
}
|
|
|
|
if (changelog.Order > combinedChangelog.Order)
|
|
{
|
|
combinedChangelog.Order = changelog.Order;
|
|
}
|
|
}
|
|
|
|
combinedChangelog.Entries = combinedChangelog.Entries.OrderBy(entry => entry.Time).ToList();
|
|
|
|
return combinedChangelog;
|
|
}
|
|
// Sunrise-End
|
|
|
|
public void PostInject()
|
|
{
|
|
_sawmill = _logManager.GetSawmill(SawmillName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to return a human-readable version number from the build.json file
|
|
/// </summary>
|
|
public string GetClientVersion()
|
|
{
|
|
var fork = _configManager.GetCVar(CVars.BuildForkId);
|
|
var version = _configManager.GetCVar(CVars.BuildVersion);
|
|
|
|
// This trimming might become annoying if down the line some codebases want to switch to a real
|
|
// version format like "104.11.3" while others are still using the git hashes
|
|
if (version.Length > 7)
|
|
version = version[..7];
|
|
|
|
if (string.IsNullOrEmpty(version) || string.IsNullOrEmpty(fork))
|
|
return Loc.GetString("changelog-version-unknown");
|
|
|
|
return Loc.GetString("changelog-version-tag",
|
|
("fork", fork),
|
|
("version", version));
|
|
}
|
|
|
|
[DataDefinition]
|
|
public sealed partial class Changelog
|
|
{
|
|
/// <summary>
|
|
/// The name to use for this changelog.
|
|
/// If left unspecified, the name of the file is used instead.
|
|
/// Used during localization to find the user-displayed name of this changelog.
|
|
/// </summary>
|
|
[DataField("Name")]
|
|
public string Name = string.Empty;
|
|
|
|
/// <summary>
|
|
/// The individual entries in this changelog.
|
|
/// These are not kept around in memory in the changelog manager.
|
|
/// </summary>
|
|
[DataField("Entries")]
|
|
public List<ChangelogEntry> Entries = new();
|
|
|
|
/// <summary>
|
|
/// Whether or not this changelog will be displayed as a tab to non-admins.
|
|
/// These are still loaded by all clients, but not shown if they aren't an admin,
|
|
/// as they do not contain sensitive data and are publicly visible on GitHub.
|
|
/// </summary>
|
|
[DataField("AdminOnly")]
|
|
public bool AdminOnly;
|
|
|
|
/// <summary>
|
|
/// Used when ordering the changelog tabs for the user to see.
|
|
/// Larger numbers are displayed later, smaller numbers are displayed earlier.
|
|
/// </summary>
|
|
[DataField("Order")]
|
|
public int Order;
|
|
}
|
|
|
|
[DataDefinition]
|
|
public sealed partial class ChangelogEntry
|
|
{
|
|
[DataField("id")]
|
|
public int Id { get; private set; }
|
|
|
|
[DataField("author")]
|
|
public string Author { get; private set; } = "";
|
|
|
|
[DataField]
|
|
public DateTime Time { get; private set; }
|
|
|
|
[DataField("changes")]
|
|
public List<ChangelogChange> Changes { get; private set; } = default!;
|
|
}
|
|
|
|
[DataDefinition]
|
|
public sealed partial class ChangelogChange
|
|
{
|
|
[DataField("type")]
|
|
public ChangelogLineType Type { get; private set; }
|
|
|
|
[DataField("message")]
|
|
public string Message { get; private set; } = "";
|
|
}
|
|
|
|
public enum ChangelogLineType
|
|
{
|
|
Add,
|
|
Remove,
|
|
Fix,
|
|
Tweak,
|
|
}
|
|
}
|
|
}
|