mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
* oops
* fixes serialization il
* copytest
* typo & misc fixes
* 139 moment
* boxing
* mesa dum
* stuff
* goodbye bad friend
* last commit before the big (4) rewrite
* adds datanodes
* kills yamlobjserializer in favor of the new system
* adds more serializers, actually implements them & removes most of the last of the old system
* changed yamlfieldattribute namespace
* adds back iselfserialize
* refactors consts&flags
* renames everything to data(field/definition)
* adds afterserialization
* help
* dataclassgen
* fuggen help me mannen
* Fix most errors on content
* Fix engine errors except map loader
* maploader & misc fix
* misc fixes
* thing
* help
* refactors datanodes
* help me mannen
* Separate ITypeSerializer into reader and writer
* Convert all type serializers
* priority
* adds alot
* il fixes
* adds robustgen
* argh
* adds array & enum serialization
* fixes dataclasses
* adds vec2i / misc fixes
* fixes inheritance
* a very notcursed todo
* fixes some custom dataclasses
* push dis
* Remove data classes
* boutta box
* yes
* Add angle and regex serializer tests
* Make TypeSerializerTest abstract
* sets up ioc etc
* remove pushinheritance
* fixes
* Merge fixes, fix yaml hot reloading
* General fixes2
* Make enum serialization ignore case
* Fix the tag not being copied in data nodes
* Fix not properly serializing flag enums
* Fix component serialization on startup
* Implement ValueDataNode ToString
* Serialization IL fixes, fix return and string equality
* Remove async from prototype manager
* Make serializing unsupported node as enum exception more descriptive
* Fix serv3 tryread casting to serializer instead of reader
* Add constructor for invalid node type exception
* Temporary fix for SERV3: Turn populate delegate into regular code
* Fix not copying the data of non primitive types
* Fix not using the data definition found in copying
* Make ISerializationHooks require explicit implementations
* Add test for serialization inheritance
* Improve IsOverridenIn method
* Fix error message when a data definition is null
* Add method to cast a read value in Serv3Manager
* Rename IServ3Manager to ISerializationManager
* Rename usages of serv3manager, add generic copy method
* Fix IL copy method lookup
* Rename old usages of serv3manager
* Add ITypeCopier
* resistance is futile
* we will conquer this codebase
* Add copy method to all serializers
* Make primitive mismatch error message more descriptive
* bing bong im going to freacking heck
* oopsie moment
* hello are you interested in my wares
* does generic serializers under new architecture
* Convert every non generic serializer to the new format, general fixes
* Update usgaes of generic serializers, cleanup
* does some pushinheritance logic
* finishes pushinheritance FRAMEWORK
* shed
* Add box2, color and component registry serializer tests
* Create more deserialized types and store prototypes with their deserialized results
* Fixes and serializer updates
* Add serialization manager extensions
* adds pushinheritance
* Update all prototypes to have a parent and have consistent id/parent properties
* Fix grammar component serialization
* Add generic serializer tests
* thonk
* Add array serializer test
* Replace logger warning calls with exceptions
* fixes
* Move redundant methods to serialization manager extensions, cleanup
* Add array serialization
* fixes context
* more fixes
* argh
* inheritance
* this should do it
* fixes
* adds copiers & fixes some stuff
* copiers use context v1
* finishing copy context
* more context fixes
* Test fixes
* funky maps
* Fix server user interface component serialization
* Fix value tuple serialization
* Add copying for value types and arrays. Fix copy internal for primitives, enums and strings
* fixes
* fixes more stuff
* yes
* Make abstract/interface skips debugs instead of warnings
* Fix typo
* Make some dictionaries readonly
* Add checks for the serialization manager initializing and already being initialized
* Add base type required and usage for MeansDataDefinition and ImplicitDataDefinitionForInheritorsAttribute
* copy by ref
* Fix exception wording
* Update data field required summary with the new forbidden docs
* Use extension in map loader
* wanna erp
* Change serializing to not use il temporarily
* Make writing work with nullable types
* pushing
* check
* cuddling slaps HARD
* Add serialization priority test
* important fix
* a serialization thing
* serializer moment
* Add validation for some type serializers
* adds context
* moar context
* fixes
* Do the thing for appearance
* yoo lmao
* push haha pp
* Temporarily make copy delegate regular c# code
* Create deserialized component registry to handle not inheriting conflicting references
* YAML LINTER BABY
* ayes
* Fix sprite component norot not being default true like in latest master
* Remove redundant todos
* Add summary doc to every ISerializationManager method
* icon fixes
* Add skip hook argument to readers and copiers
* Merge fixes
* Fix ordering of arguments in read and copy reflection call
* Fix user interface components deserialization
* pew pew
* i am going to HECK
* Add MustUseReturnValue to copy-over methods
* Make serialization log calls use the same sawmill
* gamin
* Fix doc errors in ISerializationManager.cs
* goodbye brave soldier
* fixes
* WIP merge fixes and entity serialization
* aaaaaaaaaaaaaaa
* aaaaaaaaaaaaaaa
* adds inheritancebehaviour
* test/datafield fixes
* forgot that one
* adds more verbose validation
* This fixes the YAML hot reloading
* Replace yield break with Enumerable.Empty
* adds copiers
* aaaaaaaaaaaaa
* array fix
priority fix
misc fixes
* fix(?)
* fix.
* funny map serialization (wip)
* funny map serialization (wip)
* Add TODO
* adds proper info the validation
* Make yaml linter 5 times faster (~80% less execution time)
* Improves the error message for missing fields in the linter
* Include component name in unknown component type error node
* adds alwaysrelevant usa
* fixes mapsaving
* moved surpressor to analyzers proj
* warning cleanup & moves surpressor
* removes old msbuild targets
* Revert "Make yaml linter 5 times faster (~80% less execution time)"
This reverts commit 2ee4cc2c26.
* Add serialization to RobustServerSimulation and mock reflection methods
Fixes container tests
* Fix nullability warnings
* Improve yaml linter message feedback
* oops moment
* Add IEquatable, IComparable, ToString and operators to DataPosition
Rename it to NodeMark
Make it a readonly struct
* Remove try catch from enum parsing
* Make dependency management in serialization less bad
* Make dependencies an argument instead of a property on the serialization manager
* Clean up type serializers
* Improve validation messages and resourc epath checking
* Fix sprite error message
* reached perfection
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
Co-authored-by: Vera Aguilera Puerto <zddm@outlook.es>
1113 lines
38 KiB
C#
1113 lines
38 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Runtime;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using Robust.Client.Input;
|
|
using Robust.Client.Debugging;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.ResourceManagement;
|
|
using Robust.Client.UserInterface;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.CustomControls;
|
|
using Robust.Shared.Asynchronous;
|
|
using Robust.Shared.Console;
|
|
using Robust.Shared.ContentPack;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Maths;
|
|
using Robust.Shared.Network;
|
|
using Robust.Shared.Reflection;
|
|
using Robust.Shared.Serialization;
|
|
using Robust.Shared.Utility;
|
|
using Robust.Shared.ViewVariables;
|
|
|
|
namespace Robust.Client.Console.Commands
|
|
{
|
|
internal class DumpEntitiesCommand : IConsoleCommand
|
|
{
|
|
public string Command => "dumpentities";
|
|
public string Help => "Dump entity list";
|
|
public string Description => "Dumps entity list of UIDs and prototype.";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var entityManager = IoCManager.Resolve<IEntityManager>();
|
|
|
|
foreach (var e in entityManager.GetEntities().OrderBy(e => e.Uid))
|
|
{
|
|
shell.WriteLine($"entity {e.Uid}, {e.Prototype?.ID}, {e.Transform.Coordinates}.");
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class GetComponentRegistrationCommand : IConsoleCommand
|
|
{
|
|
public string Command => "getcomponentregistration";
|
|
public string Help => "Usage: getcomponentregistration <componentName>";
|
|
public string Description => "Gets component registration information";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length < 1)
|
|
{
|
|
shell.WriteLine(Help);
|
|
return;
|
|
}
|
|
|
|
var componentFactory = IoCManager.Resolve<IComponentFactory>();
|
|
|
|
try
|
|
{
|
|
var registration = componentFactory.GetRegistration(args[0]);
|
|
|
|
var message = new StringBuilder($"'{registration.Name}': (type: {registration.Type}, ");
|
|
if (registration.NetID == null)
|
|
{
|
|
message.Append("no Net ID");
|
|
}
|
|
else
|
|
{
|
|
message.Append($"net ID: {registration.NetID}");
|
|
}
|
|
|
|
message.Append($", NSE: {registration.NetworkSynchronizeExistence}, references:");
|
|
|
|
shell.WriteLine(message.ToString());
|
|
|
|
foreach (var type in registration.References)
|
|
{
|
|
shell.WriteLine($" {type}");
|
|
}
|
|
}
|
|
catch (UnknownComponentException)
|
|
{
|
|
shell.WriteError($"No registration found for '{args[0]}'");
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class ToggleMonitorCommand : IConsoleCommand
|
|
{
|
|
public string Command => "monitor";
|
|
|
|
public string Help =>
|
|
"Usage: monitor <name>\nPossible monitors are: fps, net, bandwidth, coord, time, frames, mem, clyde, input";
|
|
|
|
public string Description => "Toggles a debug monitor in the F3 menu.";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var monitor = IoCManager.Resolve<IUserInterfaceManager>().DebugMonitors;
|
|
|
|
if (args.Length != 1)
|
|
{
|
|
shell.WriteLine(Help);
|
|
return;
|
|
}
|
|
|
|
switch (args[0])
|
|
{
|
|
case "fps":
|
|
monitor.ShowFPS ^= true;
|
|
break;
|
|
case "net":
|
|
monitor.ShowNet ^= true;
|
|
break;
|
|
case "bandwidth":
|
|
monitor.ShowNetBandwidth ^= true;
|
|
break;
|
|
case "coord":
|
|
monitor.ShowCoords ^= true;
|
|
break;
|
|
case "time":
|
|
monitor.ShowTime ^= true;
|
|
break;
|
|
case "frames":
|
|
monitor.ShowFrameGraph ^= true;
|
|
break;
|
|
case "mem":
|
|
monitor.ShowMemory ^= true;
|
|
break;
|
|
case "clyde":
|
|
monitor.ShowClyde ^= true;
|
|
break;
|
|
case "input":
|
|
monitor.ShowInput ^= true;
|
|
break;
|
|
default:
|
|
shell.WriteLine($"Invalid key: {args[0]}");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class ExceptionCommand : IConsoleCommand
|
|
{
|
|
public string Command => "fuck";
|
|
public string Help => "Throws an exception";
|
|
public string Description => "Throws an exception";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
throw new InvalidOperationException("Fuck");
|
|
}
|
|
}
|
|
|
|
internal class ShowBoundingBoxesCommand : IConsoleCommand
|
|
{
|
|
public string Command => "showbb";
|
|
public string Help => "";
|
|
public string Description => "Enables debug drawing over all bounding boxes in the game, showing their size.";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var mgr = IoCManager.Resolve<IDebugDrawing>();
|
|
mgr.DebugColliders = !mgr.DebugColliders;
|
|
}
|
|
}
|
|
|
|
internal class ShowPositionsCommand : IConsoleCommand
|
|
{
|
|
public string Command => "showpos";
|
|
public string Help => "";
|
|
public string Description => "Enables debug drawing over all entity positions in the game.";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var mgr = IoCManager.Resolve<IDebugDrawing>();
|
|
mgr.DebugPositions = !mgr.DebugPositions;
|
|
}
|
|
}
|
|
|
|
internal class ShowRayCommand : IConsoleCommand
|
|
{
|
|
public string Command => "showrays";
|
|
public string Help => "Usage: showrays <raylifetime>";
|
|
public string Description => "Toggles debug drawing of physics rays. An integer for <raylifetime> must be provided";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length != 1)
|
|
{
|
|
shell.WriteLine(Help);
|
|
return;
|
|
}
|
|
|
|
if (!int.TryParse(args[0], out var id))
|
|
{
|
|
shell.WriteError($"{args[0]} is not a valid integer.");
|
|
return;
|
|
}
|
|
|
|
var mgr = IoCManager.Resolve<IDebugDrawingManager>();
|
|
mgr.DebugDrawRays = !mgr.DebugDrawRays;
|
|
shell.WriteError("Toggled showing rays to:" + mgr.DebugDrawRays.ToString());
|
|
mgr.DebugRayLifetime = TimeSpan.FromSeconds((double)int.Parse(args[0], CultureInfo.InvariantCulture));
|
|
}
|
|
}
|
|
|
|
internal class DisconnectCommand : IConsoleCommand
|
|
{
|
|
public string Command => "disconnect";
|
|
public string Help => "";
|
|
public string Description => "Immediately disconnect from the server and go back to the main menu.";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
IoCManager.Resolve<IClientNetManager>().ClientDisconnect("Disconnect command used.");
|
|
}
|
|
}
|
|
|
|
internal class EntityInfoCommand : IConsoleCommand
|
|
{
|
|
public string Command => "entfo";
|
|
|
|
public string Help =>
|
|
"entfo <entityuid>\nThe entity UID can be prefixed with 'c' to convert it to a client entity UID.";
|
|
|
|
public string Description => "Displays verbose diagnostics for an entity.";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length != 1)
|
|
{
|
|
shell.WriteLine(Help);
|
|
return;
|
|
}
|
|
|
|
if ((!new Regex(@"^c?[0-9]+$").IsMatch(args[0])))
|
|
{
|
|
shell.WriteError("Malformed UID");
|
|
return;
|
|
}
|
|
|
|
var uid = EntityUid.Parse(args[0]);
|
|
var entmgr = IoCManager.Resolve<IEntityManager>();
|
|
if (!entmgr.TryGetEntity(uid, out var entity))
|
|
{
|
|
shell.WriteError("That entity does not exist. Sorry lad.");
|
|
return;
|
|
}
|
|
|
|
shell.WriteLine($"{entity.Uid}: {entity.Prototype?.ID}/{entity.Name}");
|
|
shell.WriteLine($"init/del/lmt: {entity.Initialized}/{entity.Deleted}/{entity.LastModifiedTick}");
|
|
foreach (var component in entity.GetAllComponents())
|
|
{
|
|
shell.WriteLine(component.ToString() ?? "");
|
|
if (component is IComponentDebug debug)
|
|
{
|
|
foreach (var line in debug.GetDebugString().Split('\n'))
|
|
{
|
|
if (string.IsNullOrWhiteSpace(line))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
shell.WriteLine("\t" + line);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class SnapGridGetCell : IConsoleCommand
|
|
{
|
|
public string Command => "sggcell";
|
|
public string Help => "sggcell <gridID> <vector2i> [offset]\nThat vector2i param is in the form x<int>,y<int>.";
|
|
public string Description => "Lists entities on a snap grid cell.";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length != 2 && args.Length != 3)
|
|
{
|
|
shell.WriteLine(Help);
|
|
return;
|
|
}
|
|
|
|
string gridId = args[0];
|
|
string indices = args[1];
|
|
string offset = args.Length == 3 ? args[2] : "Center";
|
|
|
|
if (!int.TryParse(args[0], out var id))
|
|
{
|
|
shell.WriteError($"{args[0]} is not a valid integer.");
|
|
return;
|
|
}
|
|
|
|
if (!new Regex(@"^-?[0-9]+,-?[0-9]+$").IsMatch(indices))
|
|
{
|
|
shell.WriteError("mapIndicies must be of form x<int>,y<int>");
|
|
return;
|
|
}
|
|
|
|
SnapGridOffset selectedOffset;
|
|
if (Enum.IsDefined(typeof(SnapGridOffset), offset))
|
|
{
|
|
selectedOffset = (SnapGridOffset)Enum.Parse(typeof(SnapGridOffset), offset);
|
|
}
|
|
else
|
|
{
|
|
shell.WriteError("given offset type is not defined");
|
|
return;
|
|
}
|
|
|
|
var mapMan = IoCManager.Resolve<IMapManager>();
|
|
|
|
if (mapMan.GridExists(new GridId(int.Parse(gridId, CultureInfo.InvariantCulture))))
|
|
{
|
|
foreach (var entity in
|
|
mapMan.GetGrid(new GridId(int.Parse(gridId, CultureInfo.InvariantCulture))).GetSnapGridCell(
|
|
new Vector2i(
|
|
int.Parse(indices.Split(',')[0], CultureInfo.InvariantCulture),
|
|
int.Parse(indices.Split(',')[1], CultureInfo.InvariantCulture)),
|
|
selectedOffset))
|
|
{
|
|
shell.WriteLine(entity.Owner.Uid.ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
shell.WriteError("grid does not exist");
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class SetPlayerName : IConsoleCommand
|
|
{
|
|
public string Command => "overrideplayername";
|
|
public string Description => "Changes the name used when attempting to connect to the server.";
|
|
public string Help => Command + " <name>";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length < 1)
|
|
{
|
|
shell.WriteLine(Help);
|
|
return;
|
|
}
|
|
var client = IoCManager.Resolve<IBaseClient>();
|
|
client.PlayerNameOverride = args[0];
|
|
|
|
shell.WriteLine($"Overriding player name to \"{args[0]}\".");
|
|
}
|
|
}
|
|
|
|
internal class LoadResource : IConsoleCommand
|
|
{
|
|
public string Command => "ldrsc";
|
|
public string Description => "Pre-caches a resource.";
|
|
public string Help => "ldrsc <path> <type>";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length < 2)
|
|
{
|
|
shell.WriteLine(Help);
|
|
return;
|
|
}
|
|
var resourceCache = IoCManager.Resolve<IResourceCache>();
|
|
var reflection = IoCManager.Resolve<IReflectionManager>();
|
|
Type type;
|
|
|
|
try
|
|
{
|
|
type = reflection.LooseGetType(args[1]);
|
|
}
|
|
catch(ArgumentException)
|
|
{
|
|
shell.WriteError("Unable to find type");
|
|
return;
|
|
}
|
|
|
|
var getResourceMethod =
|
|
resourceCache
|
|
.GetType()
|
|
.GetMethod("GetResource", new[] { typeof(string), typeof(bool) });
|
|
DebugTools.Assert(getResourceMethod != null);
|
|
var generic = getResourceMethod!.MakeGenericMethod(type);
|
|
generic.Invoke(resourceCache, new object[] { args[0], true });
|
|
}
|
|
}
|
|
|
|
internal class ReloadResource : IConsoleCommand
|
|
{
|
|
public string Command => "rldrsc";
|
|
public string Description => "Reloads a resource.";
|
|
public string Help => "rldrsc <path> <type>";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length < 2)
|
|
{
|
|
shell.WriteLine(Help);
|
|
return;
|
|
}
|
|
var resourceCache = IoCManager.Resolve<IResourceCache>();
|
|
var reflection = IoCManager.Resolve<IReflectionManager>();
|
|
|
|
Type type;
|
|
try
|
|
{
|
|
type = reflection.LooseGetType(args[1]);
|
|
}
|
|
catch(ArgumentException)
|
|
{
|
|
shell.WriteError("Unable to find type");
|
|
return;
|
|
}
|
|
|
|
var getResourceMethod = resourceCache.GetType().GetMethod("ReloadResource", new[] { typeof(string) });
|
|
DebugTools.Assert(getResourceMethod != null);
|
|
var generic = getResourceMethod!.MakeGenericMethod(type);
|
|
generic.Invoke(resourceCache, new object[] { args[0] });
|
|
}
|
|
}
|
|
|
|
internal class GridTileCount : IConsoleCommand
|
|
{
|
|
public string Command => "gridtc";
|
|
public string Description => "Gets the tile count of a grid";
|
|
public string Help => "Usage: gridtc <gridId>";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length != 1)
|
|
{
|
|
shell.WriteLine(Help);
|
|
return;
|
|
}
|
|
|
|
if (!int.TryParse(args[0], out var id))
|
|
{
|
|
shell.WriteLine($"{args[0]} is not a valid integer.");
|
|
return;
|
|
}
|
|
|
|
var gridId = new GridId(int.Parse(args[0]));
|
|
var mapManager = IoCManager.Resolve<IMapManager>();
|
|
|
|
if (mapManager.TryGetGrid(gridId, out var grid))
|
|
{
|
|
shell.WriteLine(mapManager.GetGrid(gridId).GetAllTiles().Count().ToString());
|
|
}
|
|
else
|
|
{
|
|
shell.WriteError($"No grid exists with id {id}");
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class GuiDumpCommand : IConsoleCommand
|
|
{
|
|
public string Command => "guidump";
|
|
public string Description => "Dump GUI tree to /guidump.txt in user data.";
|
|
public string Help => "guidump";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var root = IoCManager.Resolve<IUserInterfaceManager>().RootControl;
|
|
var res = IoCManager.Resolve<IResourceManager>();
|
|
|
|
using (var stream = res.UserData.Create(new ResourcePath("/guidump.txt")))
|
|
using (var writer = new StreamWriter(stream, EncodingHelpers.UTF8))
|
|
{
|
|
_writeNode(root, 0, writer);
|
|
}
|
|
|
|
shell.WriteLine("Saved guidump");
|
|
}
|
|
|
|
private static void _writeNode(Control control, int indents, TextWriter writer)
|
|
{
|
|
var indentation = new string(' ', indents * 2);
|
|
writer.WriteLine("{0}{1}", indentation, control);
|
|
foreach (var (key, value) in _propertyValuesFor(control))
|
|
{
|
|
writer.WriteLine("{2} * {0}: {1}", key, value, indentation);
|
|
}
|
|
|
|
foreach (var child in control.Children)
|
|
{
|
|
_writeNode(child, indents + 1, writer);
|
|
}
|
|
}
|
|
|
|
private static List<(string, string)> _propertyValuesFor(Control control)
|
|
{
|
|
var members = new List<(string, string)>();
|
|
var type = control.GetType();
|
|
|
|
foreach (var fieldInfo in type.GetAllFields())
|
|
{
|
|
if (fieldInfo.GetCustomAttribute<ViewVariablesAttribute>() == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
members.Add((fieldInfo.Name, fieldInfo.GetValue(control)?.ToString() ?? "null"));
|
|
}
|
|
|
|
foreach (var propertyInfo in type.GetAllProperties())
|
|
{
|
|
if (propertyInfo.GetCustomAttribute<ViewVariablesAttribute>() == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
members.Add((propertyInfo.Name, propertyInfo.GetValue(control)?.ToString() ?? "null"));
|
|
}
|
|
|
|
foreach (var (attachedProperty, value) in control.AllAttachedProperties)
|
|
{
|
|
members.Add(($"{attachedProperty.OwningType.Name}.{attachedProperty.Name}",
|
|
value?.ToString() ?? "null"));
|
|
}
|
|
|
|
members.Sort((a, b) => string.Compare(a.Item1, b.Item1, StringComparison.Ordinal));
|
|
return members;
|
|
}
|
|
}
|
|
|
|
internal class UITestCommand : IConsoleCommand
|
|
{
|
|
public string Command => "uitest";
|
|
public string Description => "Open a dummy UI testing window";
|
|
public string Help => "uitest";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var window = new SS14Window { MinSize = (500, 400)};
|
|
var tabContainer = new TabContainer();
|
|
window.Contents.AddChild(tabContainer);
|
|
var scroll = new ScrollContainer();
|
|
tabContainer.AddChild(scroll);
|
|
//scroll.SetAnchorAndMarginPreset(Control.LayoutPreset.Wide);
|
|
var vBox = new VBoxContainer();
|
|
scroll.AddChild(vBox);
|
|
|
|
var progressBar = new ProgressBar { MaxValue = 10, Value = 5 };
|
|
vBox.AddChild(progressBar);
|
|
|
|
var optionButton = new OptionButton();
|
|
optionButton.AddItem("Honk");
|
|
optionButton.AddItem("Foo");
|
|
optionButton.AddItem("Bar");
|
|
optionButton.AddItem("Baz");
|
|
optionButton.OnItemSelected += eventArgs => optionButton.SelectId(eventArgs.Id);
|
|
vBox.AddChild(optionButton);
|
|
|
|
var tree = new Tree { VerticalExpand = true };
|
|
var root = tree.CreateItem();
|
|
root.Text = "Honk!";
|
|
var child = tree.CreateItem();
|
|
child.Text = "Foo";
|
|
for (var i = 0; i < 20; i++)
|
|
{
|
|
child = tree.CreateItem();
|
|
child.Text = $"Bar {i}";
|
|
}
|
|
|
|
vBox.AddChild(tree);
|
|
|
|
var rich = new RichTextLabel();
|
|
var message = new FormattedMessage();
|
|
message.AddText("Foo\n");
|
|
message.PushColor(Color.Red);
|
|
message.AddText("Bar");
|
|
message.Pop();
|
|
rich.SetMessage(message);
|
|
vBox.AddChild(rich);
|
|
|
|
var itemList = new ItemList();
|
|
tabContainer.AddChild(itemList);
|
|
for (var i = 0; i < 10; i++)
|
|
{
|
|
itemList.AddItem(i.ToString());
|
|
}
|
|
|
|
var grid = new GridContainer { Columns = 3 };
|
|
tabContainer.AddChild(grid);
|
|
for (var y = 0; y < 3; y++)
|
|
{
|
|
for (var x = 0; x < 3; x++)
|
|
{
|
|
grid.AddChild(new Button
|
|
{
|
|
MinSize = (50, 50),
|
|
Text = $"{x}, {y}"
|
|
});
|
|
}
|
|
}
|
|
|
|
var group = new ButtonGroup();
|
|
var vBoxRadioButtons = new VBoxContainer();
|
|
for (var i = 0; i < 10; i++)
|
|
{
|
|
vBoxRadioButtons.AddChild(new Button
|
|
{
|
|
Text = i.ToString(),
|
|
Group = group
|
|
});
|
|
|
|
// ftftftftftftft
|
|
}
|
|
|
|
tabContainer.AddChild(vBoxRadioButtons);
|
|
|
|
TabContainer.SetTabTitle(vBoxRadioButtons, "Radio buttons!!");
|
|
|
|
tabContainer.AddChild(new VBoxContainer
|
|
{
|
|
Name = "Slider",
|
|
Children =
|
|
{
|
|
new Slider()
|
|
}
|
|
});
|
|
|
|
tabContainer.AddChild(new HSplitContainer
|
|
{
|
|
Children =
|
|
{
|
|
new PanelContainer
|
|
{
|
|
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Red},
|
|
Children =
|
|
{
|
|
new Label{ Text = "FOOBARBAZ"},
|
|
}
|
|
},
|
|
new PanelContainer
|
|
{
|
|
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Blue},
|
|
Children =
|
|
{
|
|
new Label{ Text = "FOOBARBAZ"},
|
|
}
|
|
},
|
|
}
|
|
});
|
|
|
|
window.OpenCentered();
|
|
}
|
|
}
|
|
|
|
internal class SetClipboardCommand : IConsoleCommand
|
|
{
|
|
public string Command => "setclipboard";
|
|
public string Description => "Sets the system clipboard";
|
|
public string Help => "setclipboard <text>";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var mgr = IoCManager.Resolve<IClipboardManager>();
|
|
mgr.SetText(args[0]);
|
|
}
|
|
}
|
|
|
|
internal class GetClipboardCommand : IConsoleCommand
|
|
{
|
|
public string Command => "getclipboard";
|
|
public string Description => "Gets the system clipboard";
|
|
public string Help => "getclipboard";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var mgr = IoCManager.Resolve<IClipboardManager>();
|
|
shell.WriteLine(mgr.GetText());
|
|
}
|
|
}
|
|
|
|
internal class ToggleLight : IConsoleCommand
|
|
{
|
|
public string Command => "togglelight";
|
|
public string Description => "Toggles light rendering.";
|
|
public string Help => "togglelight";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var mgr = IoCManager.Resolve<ILightManager>();
|
|
if (!mgr.LockConsoleAccess)
|
|
mgr.Enabled = !mgr.Enabled;
|
|
}
|
|
}
|
|
|
|
internal class ToggleFOV : IConsoleCommand
|
|
{
|
|
public string Command => "togglefov";
|
|
public string Description => "Toggles fov for client.";
|
|
public string Help => "togglefov";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var mgr = IoCManager.Resolve<IEyeManager>();
|
|
if (mgr.CurrentEye != null)
|
|
mgr.CurrentEye.DrawFov = !mgr.CurrentEye.DrawFov;
|
|
}
|
|
}
|
|
|
|
internal class ToggleHardFOV : IConsoleCommand
|
|
{
|
|
public string Command => "togglehardfov";
|
|
public string Description => "Toggles hard fov for client (for debugging space-station-14#2353).";
|
|
public string Help => "togglehardfov";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var mgr = IoCManager.Resolve<ILightManager>();
|
|
if (!mgr.LockConsoleAccess)
|
|
mgr.DrawHardFov = !mgr.DrawHardFov;
|
|
}
|
|
}
|
|
|
|
internal class ToggleShadows : IConsoleCommand
|
|
{
|
|
public string Command => "toggleshadows";
|
|
public string Description => "Toggles shadow rendering.";
|
|
public string Help => "toggleshadows";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var mgr = IoCManager.Resolve<ILightManager>();
|
|
if (!mgr.LockConsoleAccess)
|
|
mgr.DrawShadows = !mgr.DrawShadows;
|
|
}
|
|
}
|
|
internal class ToggleLightBuf : IConsoleCommand
|
|
{
|
|
public string Command => "togglelightbuf";
|
|
public string Description => "Toggles lighting rendering. This includes shadows but not FOV.";
|
|
public string Help => "togglelightbuf";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var mgr = IoCManager.Resolve<ILightManager>();
|
|
if (!mgr.LockConsoleAccess)
|
|
mgr.DrawLighting = !mgr.DrawLighting;
|
|
}
|
|
}
|
|
|
|
internal class GcCommand : IConsoleCommand
|
|
{
|
|
public string Command => "gc";
|
|
public string Description => "Run the GC.";
|
|
public string Help => "gc [generation]";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length == 0)
|
|
{
|
|
GC.Collect();
|
|
}
|
|
else
|
|
{
|
|
if (int.TryParse(args[0], out int result))
|
|
GC.Collect(result);
|
|
else
|
|
shell.WriteError("Failed to parse argument.");
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class GcFullCommand : IConsoleCommand
|
|
{
|
|
public string Command => "gcf";
|
|
public string Description => "Run the GC, fully, compacting LOH and everything.";
|
|
public string Help => "gcf";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
|
GC.Collect(2, GCCollectionMode.Forced, true, true);
|
|
}
|
|
}
|
|
|
|
internal class GcModeCommand : IConsoleCommand
|
|
{
|
|
|
|
public string Command => "gc_mode";
|
|
|
|
public string Description => "Change/Read the GC Latency mode.";
|
|
|
|
public string Help => "gc_mode\nSee current GC Latencymode\ngc_mode [type]\n Change GC Latency mode to [type]";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var prevMode = GCSettings.LatencyMode;
|
|
if (args.Length == 0)
|
|
{
|
|
shell.WriteLine($"current gc latency mode: {(int) prevMode} ({prevMode})");
|
|
shell.WriteLine("possible modes:");
|
|
foreach (int mode in (int[]) Enum.GetValues(typeof(GCLatencyMode)))
|
|
{
|
|
shell.WriteLine($" {mode}: {Enum.GetName(typeof(GCLatencyMode), mode)}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GCLatencyMode mode;
|
|
if (char.IsDigit(args[0][0]) && int.TryParse(args[0], out var modeNum))
|
|
{
|
|
mode = (GCLatencyMode) modeNum;
|
|
}
|
|
else if (!Enum.TryParse(args[0], true, out mode))
|
|
{
|
|
shell.WriteLine($"unknown gc latency mode: {args[0]}");
|
|
return;
|
|
}
|
|
|
|
shell.WriteLine($"attempting gc latency mode change: {(int) prevMode} ({prevMode}) -> {(int) mode} ({mode})");
|
|
GCSettings.LatencyMode = mode;
|
|
shell.WriteLine($"resulting gc latency mode: {(int) GCSettings.LatencyMode} ({GCSettings.LatencyMode})");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
internal class SerializeStatsCommand : IConsoleCommand
|
|
{
|
|
|
|
public string Command => "szr_stats";
|
|
|
|
public string Description => "Report serializer statistics.";
|
|
|
|
public string Help => "szr_stats";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
|
|
shell.WriteLine($"serialized: {RobustSerializer.BytesSerialized} bytes, {RobustSerializer.ObjectsSerialized} objects");
|
|
shell.WriteLine($"largest serialized: {RobustSerializer.LargestObjectSerializedBytes} bytes, {RobustSerializer.LargestObjectSerializedType} objects");
|
|
shell.WriteLine($"deserialized: {RobustSerializer.BytesDeserialized} bytes, {RobustSerializer.ObjectsDeserialized} objects");
|
|
shell.WriteLine($"largest serialized: {RobustSerializer.LargestObjectDeserializedBytes} bytes, {RobustSerializer.LargestObjectDeserializedType} objects");
|
|
}
|
|
|
|
}
|
|
|
|
internal class ChunkInfoCommand : IConsoleCommand
|
|
{
|
|
public string Command => "chunkinfo";
|
|
public string Description => "Gets info about a chunk under your mouse cursor.";
|
|
public string Help => Command;
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var mapMan = IoCManager.Resolve<IMapManager>();
|
|
var inputMan = IoCManager.Resolve<IInputManager>();
|
|
var eyeMan = IoCManager.Resolve<IEyeManager>();
|
|
|
|
var mousePos = eyeMan.ScreenToMap(inputMan.MouseScreenPosition);
|
|
|
|
if (!mapMan.TryFindGridAt(mousePos, out var grid))
|
|
{
|
|
shell.WriteLine("No grid under your mouse cursor.");
|
|
return;
|
|
}
|
|
|
|
var internalGrid = (IMapGridInternal)grid;
|
|
|
|
var chunkIndex = grid.LocalToChunkIndices(grid.MapToGrid(mousePos));
|
|
var chunk = internalGrid.GetChunk(chunkIndex);
|
|
|
|
shell.WriteLine($"worldBounds: {chunk.CalcWorldBounds()} localBounds: {chunk.CalcLocalBounds()}");
|
|
}
|
|
}
|
|
|
|
internal class ReloadShadersCommand : IConsoleCommand
|
|
{
|
|
|
|
public string Command => "rldshader";
|
|
|
|
public string Description => "Reloads all shaders";
|
|
|
|
public string Help => "rldshader";
|
|
|
|
public static Dictionary<string, FileSystemWatcher>? _watchers;
|
|
|
|
public static ConcurrentDictionary<string, bool>? _reloadShadersQueued = new();
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
IResourceCacheInternal resC;
|
|
if (args.Length == 1)
|
|
{
|
|
if (args[0] == "+watch")
|
|
{
|
|
if (_watchers != null)
|
|
{
|
|
shell.WriteLine("Already watching.");
|
|
return;
|
|
}
|
|
resC = IoCManager.Resolve<IResourceCacheInternal>();
|
|
|
|
_watchers = new Dictionary<string, FileSystemWatcher>();
|
|
|
|
var stringComparer = PathHelpers.IsFileSystemCaseSensitive()
|
|
? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase;
|
|
|
|
var reversePathResolution = new ConcurrentDictionary<string, HashSet<ResourcePath>>(stringComparer);
|
|
|
|
var taskManager = IoCManager.Resolve<ITaskManager>();
|
|
|
|
var shaderCount = 0;
|
|
var created = 0;
|
|
var dirs = new ConcurrentDictionary<string, SortedSet<string>>(stringComparer);
|
|
foreach (var (path, src) in resC.GetAllResources<ShaderSourceResource>())
|
|
{
|
|
if (!resC.TryGetDiskFilePath(path, out var fullPath))
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
reversePathResolution.GetOrAdd(fullPath, _ => new HashSet<ResourcePath>()).Add(path);
|
|
|
|
var dir = Path.GetDirectoryName(fullPath)!;
|
|
var fileName = Path.GetFileName(fullPath);
|
|
dirs.GetOrAdd(dir, _ => new SortedSet<string>(stringComparer))
|
|
.Add(fileName);
|
|
|
|
foreach (var inc in src.ParsedShader.Includes)
|
|
{
|
|
if (!resC.TryGetDiskFilePath(inc, out var incFullPath))
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
reversePathResolution.GetOrAdd(incFullPath, _ => new HashSet<ResourcePath>()).Add(path);
|
|
|
|
var incDir = Path.GetDirectoryName(incFullPath)!;
|
|
var incFileName = Path.GetFileName(incFullPath);
|
|
dirs.GetOrAdd(incDir, _ => new SortedSet<string>(stringComparer))
|
|
.Add(incFileName);
|
|
}
|
|
|
|
++shaderCount;
|
|
}
|
|
|
|
foreach (var (dir, files) in dirs)
|
|
{
|
|
if (_watchers.TryGetValue(dir, out var watcher))
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
watcher = new FileSystemWatcher(dir);
|
|
watcher.Changed += (_, ev) =>
|
|
{
|
|
if (_reloadShadersQueued!.TryAdd(ev.FullPath, true))
|
|
{
|
|
taskManager.RunOnMainThread(() =>
|
|
{
|
|
var resPaths = reversePathResolution[ev.FullPath];
|
|
foreach (var resPath in resPaths)
|
|
{
|
|
try
|
|
{
|
|
IoCManager.Resolve<IResourceCache>()
|
|
.ReloadResource<ShaderSourceResource>(resPath);
|
|
shell.WriteLine($"Reloaded shader: {resPath}");
|
|
}
|
|
catch (Exception)
|
|
{
|
|
shell.WriteLine($"Failed to reload shader: {resPath}");
|
|
}
|
|
|
|
_reloadShadersQueued.TryRemove(ev.FullPath, out var _);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
foreach (var file in files)
|
|
{
|
|
watcher.Filters.Add(file);
|
|
}
|
|
|
|
watcher.EnableRaisingEvents = true;
|
|
|
|
_watchers.Add(dir, watcher);
|
|
++created;
|
|
}
|
|
|
|
shell.WriteLine($"Created {created} shader directory watchers for {shaderCount} shaders.");
|
|
|
|
return;
|
|
}
|
|
|
|
if (args[0] == "-watch")
|
|
{
|
|
if (_watchers == null)
|
|
{
|
|
shell.WriteLine("No shader directory watchers active.");
|
|
return;
|
|
}
|
|
|
|
var disposed = 0;
|
|
foreach (var (_, watcher) in _watchers)
|
|
{
|
|
++disposed;
|
|
watcher.Dispose();
|
|
}
|
|
|
|
_watchers = null;
|
|
|
|
shell.WriteLine($"Disposed of {disposed} shader directory watchers.");
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (args.Length > 1)
|
|
{
|
|
shell.WriteLine("Not implemented.");
|
|
return;
|
|
}
|
|
|
|
shell.WriteLine("Reloading content shader resources...");
|
|
|
|
resC = IoCManager.Resolve<IResourceCacheInternal>();
|
|
|
|
foreach (var (path, _) in resC.GetAllResources<ShaderSourceResource>())
|
|
{
|
|
try
|
|
{
|
|
resC.ReloadResource<ShaderSourceResource>(path);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
shell.WriteLine($"Failed to reload shader: {path}");
|
|
}
|
|
}
|
|
|
|
shell.WriteLine("Done.");
|
|
}
|
|
|
|
}
|
|
|
|
internal class ClydeDebugLayerCommand : IConsoleCommand
|
|
{
|
|
public string Command => "cldbglyr";
|
|
public string Description => "Toggle fov and light debug layers";
|
|
public string Help => "cldbglyr <layer>: Toggle <layer>\ncldbglyr: Turn all Layers off";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
var clyde = IoCManager.Resolve<IClydeInternal>();
|
|
|
|
if (args.Length < 1)
|
|
{
|
|
clyde.DebugLayers = ClydeDebugLayers.None;
|
|
return;
|
|
}
|
|
|
|
clyde.DebugLayers = args[0] switch
|
|
{
|
|
"fov" => ClydeDebugLayers.Fov,
|
|
"light" => ClydeDebugLayers.Light,
|
|
_ => ClydeDebugLayers.None
|
|
};
|
|
}
|
|
}
|
|
|
|
internal class GetKeyInfoCommand : IConsoleCommand
|
|
{
|
|
public string Command => "keyinfo";
|
|
public string Description => "Keys key info for a key";
|
|
public string Help => "keyinfo <Key>";
|
|
|
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
{
|
|
if (args.Length != 1)
|
|
{
|
|
shell.WriteLine(Help);
|
|
return;
|
|
}
|
|
|
|
var clyde = IoCManager.Resolve<IClydeInternal>();
|
|
|
|
if (Enum.TryParse(typeof(Keyboard.Key), args[0], true, out var parsed))
|
|
{
|
|
var key = (Keyboard.Key) parsed!;
|
|
|
|
var name = clyde.GetKeyName(key);
|
|
var scanCode = clyde.GetKeyScanCode(key);
|
|
var nameScanCode = clyde.GetKeyNameScanCode(scanCode);
|
|
|
|
shell.WriteLine($"name: '{name}' scan code: '{scanCode}' name via scan code: '{nameScanCode}'");
|
|
}
|
|
else if (int.TryParse(args[0], out var scanCode))
|
|
{
|
|
var nameScanCode = clyde.GetKeyNameScanCode(scanCode);
|
|
shell.WriteLine($"name via scan code: '{nameScanCode}'");
|
|
}
|
|
}
|
|
}
|
|
}
|