Merge branch 'master' into kitchen

This commit is contained in:
Pieter-Jan Briers
2020-05-05 11:35:20 +02:00
committed by GitHub
112 changed files with 2184 additions and 408 deletions

View File

@@ -211,19 +211,19 @@ namespace Content.Client.Chat
case OOCAlias:
{
var conInput = text.Substring(1);
_console.ProcessCommand($"ooc \"{conInput}\"");
_console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\"");
break;
}
case MeAlias:
{
var conInput = text.Substring(1);
_console.ProcessCommand($"me \"{conInput}\"");
_console.ProcessCommand($"me \"{CommandParsing.Escape(conInput)}\"");
break;
}
default:
{
var conInput = _currentChatBox.DefaultChatFormat != null
? string.Format(_currentChatBox.DefaultChatFormat, text)
? string.Format(_currentChatBox.DefaultChatFormat, CommandParsing.Escape(text))
: text;
_console.ProcessCommand(conInput);
break;

View File

@@ -31,6 +31,7 @@ namespace Content.Client
IoCManager.Register<IClientPreferencesManager, ClientPreferencesManager>();
IoCManager.Register<IItemSlotManager, ItemSlotManager>();
IoCManager.Register<IStylesheetManager, StylesheetManager>();
IoCManager.Register<IScreenshotHook, ScreenshotHook>();
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Content.Client.Interfaces;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared;
using Robust.Client.Interfaces.Console;
using Robust.Client.Interfaces.Graphics.ClientEye;
@@ -57,7 +58,11 @@ namespace Content.Client
public void PopupMessage(ScreenCoordinates coordinates, string message)
{
var label = new PopupLabel {Text = message};
var label = new PopupLabel
{
Text = message,
StyleClasses = { StyleNano.StyleClassPopupMessage },
};
var minimumSize = label.CombinedMinimumSize;
LayoutContainer.SetPosition(label, label.InitialPos = coordinates.Position - minimumSize / 2);
_userInterfaceManager.PopupRoot.AddChild(label);

View File

@@ -12,6 +12,7 @@ using Content.Client.UserInterface.Stylesheets;
using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.Components.Cargo;
using Content.Shared.GameObjects.Components.Chemistry;
using Content.Shared.GameObjects.Components.Gravity;
using Content.Shared.GameObjects.Components.Markers;
using Content.Shared.GameObjects.Components.Research;
using Content.Shared.GameObjects.Components.VendingMachines;
@@ -162,6 +163,8 @@ namespace Content.Client
factory.Register<SharedCargoConsoleComponent>();
factory.Register<SharedReagentDispenserComponent>();
factory.Register<SharedMicrowaveComponent>();
factory.Register<SharedGravityGeneratorComponent>();
prototypes.RegisterIgnore("material");
prototypes.RegisterIgnore("reaction"); //Chemical reactions only needed by server. Reactions checks are server-side.
prototypes.RegisterIgnore("barSign");
@@ -179,6 +182,7 @@ namespace Content.Client
IoCManager.Resolve<IParallaxManager>().LoadParallax();
IoCManager.Resolve<IBaseClient>().PlayerJoinedServer += SubscribePlayerAttachmentEvents;
IoCManager.Resolve<IStylesheetManager>().Initialize();
IoCManager.Resolve<IScreenshotHook>().Initialize();
IoCManager.InjectDependencies(this);

View File

@@ -0,0 +1,104 @@
using System;
using Content.Shared.GameObjects.Components.Gravity;
using Robust.Client.GameObjects.Components.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
namespace Content.Client.GameObjects.Components.Gravity
{
public class GravityGeneratorBoundUserInterface: BoundUserInterface
{
private GravityGeneratorWindow _window;
public bool IsOn;
public GravityGeneratorBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base (owner, uiKey)
{
SendMessage(new SharedGravityGeneratorComponent.GeneratorStatusRequestMessage());
}
protected override void Open()
{
base.Open();
IsOn = false;
_window = new GravityGeneratorWindow(this);
_window.Switch.OnPressed += (args) =>
{
SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(!IsOn));
SendMessage(new SharedGravityGeneratorComponent.GeneratorStatusRequestMessage());
};
_window.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
var castState = (SharedGravityGeneratorComponent.GeneratorState) state;
IsOn = castState.On;
_window.UpdateButton();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
}
public class GravityGeneratorWindow : SS14Window
{
public Label Status;
public Button Switch;
public GravityGeneratorBoundUserInterface Owner;
public GravityGeneratorWindow(GravityGeneratorBoundUserInterface gravityGeneratorInterface = null)
{
IoCManager.InjectDependencies(this);
Owner = gravityGeneratorInterface;
Title = Loc.GetString("Gravity Generator Control");
var vBox = new VBoxContainer
{
CustomMinimumSize = new Vector2(250, 100)
};
Status = new Label
{
Text = Loc.GetString("Current Status: " + (Owner.IsOn ? "On" : "Off")),
FontColorOverride = Owner.IsOn ? Color.ForestGreen : Color.Red
};
Switch = new Button
{
Text = Loc.GetString(Owner.IsOn ? "Turn Off" : "Turn On"),
TextAlign = Label.AlignMode.Center,
CustomMinimumSize = new Vector2(150, 60)
};
vBox.AddChild(Status);
vBox.AddChild(Switch);
Contents.AddChild(vBox);
}
public void UpdateButton()
{
Status.Text = Loc.GetString("Current Status: " + (Owner.IsOn ? "On" : "Off"));
Status.FontColorOverride = Owner.IsOn ? Color.ForestGreen : Color.Red;
Switch.Text = Loc.GetString(Owner.IsOn ? "Turn Off" : "Turn On");
}
}
}

View File

@@ -25,8 +25,6 @@ namespace Content.Client.GameObjects.EntitySystems
[UsedImplicitly]
public sealed class CombatModeSystem : SharedCombatModeSystem
{
private const float AttackTimeThreshold = 0.15f;
#pragma warning disable 649
[Dependency] private readonly IGameHud _gameHud;
[Dependency] private readonly IPlayerManager _playerManager;
@@ -37,9 +35,6 @@ namespace Content.Client.GameObjects.EntitySystems
private InputSystem _inputSystem;
public bool UseOrAttackIsDown { get; private set; }
private float _timeHeld;
public override void Initialize()
{
base.Initialize();
@@ -48,10 +43,8 @@ namespace Content.Client.GameObjects.EntitySystems
_gameHud.OnTargetingZoneChanged = OnTargetingZoneChanged;
_inputSystem = EntitySystemManager.GetEntitySystem<InputSystem>();
_inputSystem.BindMap.BindFunction(ContentKeyFunctions.UseOrAttack, new InputHandler(this));
_inputSystem.BindMap.BindFunction(ContentKeyFunctions.ToggleCombatMode,
InputCmdHandler.FromDelegate(CombatModeToggled));
_overlayManager.AddOverlay(new CombatModeOverlay(this));
}
private void CombatModeToggled(ICommonSession session)
@@ -60,20 +53,10 @@ namespace Content.Client.GameObjects.EntitySystems
{
EntityManager.RaisePredictiveEvent(
new CombatModeSystemMessages.SetCombatModeActiveMessage(!IsInCombatMode()));
// Just in case.
UseOrAttackIsDown = false;
}
}
public override void Shutdown()
{
base.Shutdown();
_overlayManager.RemoveOverlay(nameof(CombatModeOverlay));
}
private bool IsInCombatMode()
public bool IsInCombatMode()
{
var entity = _playerManager.LocalPlayer.ControlledEntity;
if (entity == null || !entity.TryGetComponent(out CombatModeComponent combatMode))
@@ -92,104 +75,6 @@ namespace Content.Client.GameObjects.EntitySystems
private void OnCombatModeChanged(bool obj)
{
EntityManager.RaisePredictiveEvent(new CombatModeSystemMessages.SetCombatModeActiveMessage(obj));
// Just in case.
UseOrAttackIsDown = false;
}
private bool HandleInputMessage(ICommonSession session, InputCmdMessage message)
{
if (!(message is FullInputCmdMessage msg))
return false;
void SendMsg(BoundKeyFunction function, BoundKeyState state)
{
var functionId = _inputManager.NetworkBindMap.KeyFunctionID(function);
var sendMsg = new FullInputCmdMessage(msg.Tick, functionId, state,
msg.Coordinates, msg.ScreenCoordinates, msg.Uid);
_inputSystem.HandleInputCommand(session, function, sendMsg);
}
// If we are not in combat mode, relay it as a regular Use instead.
if (!IsInCombatMode())
{
SendMsg(EngineKeyFunctions.Use, msg.State);
return true;
}
if (msg.State == BoundKeyState.Down)
{
UseOrAttackIsDown = true;
_timeHeld = 0;
return true;
}
// Up.
if (UseOrAttackIsDown && _timeHeld >= AttackTimeThreshold)
{
// Attack.
SendMsg(ContentKeyFunctions.Attack, BoundKeyState.Down);
SendMsg(ContentKeyFunctions.Attack, BoundKeyState.Up);
}
else
{
// Use.
SendMsg(EngineKeyFunctions.Use, BoundKeyState.Down);
SendMsg(EngineKeyFunctions.Use, BoundKeyState.Up);
}
UseOrAttackIsDown = false;
return true;
}
public override void FrameUpdate(float frameTime)
{
if (UseOrAttackIsDown)
{
_timeHeld += frameTime;
}
}
// Custom input handler type so we get the ENTIRE InputCmdMessage.
private sealed class InputHandler : InputCmdHandler
{
private readonly CombatModeSystem _combatModeSystem;
public InputHandler(CombatModeSystem combatModeSystem)
{
_combatModeSystem = combatModeSystem;
}
public override bool HandleCmdMessage(ICommonSession session, InputCmdMessage message)
{
return _combatModeSystem.HandleInputMessage(session, message);
}
}
private sealed class CombatModeOverlay : Overlay
{
private readonly CombatModeSystem _system;
public CombatModeOverlay(CombatModeSystem system) : base(nameof(CombatModeOverlay))
{
_system = system;
}
protected override void Draw(DrawingHandleBase handle)
{
var screenHandle = (DrawingHandleScreen) handle;
var mousePos = IoCManager.Resolve<IInputManager>().MouseScreenPosition;
if (_system.UseOrAttackIsDown && _system._timeHeld > AttackTimeThreshold)
{
var tex = ResC.GetTexture($"/Textures/Objects/Tools/toolbox_r.png");
screenHandle.DrawTextureRect(tex, UIBox2.FromDimensions(mousePos, tex.Size * 2));
}
}
}
}
}

View File

@@ -39,8 +39,8 @@ namespace Content.Client.GameObjects.EntitySystems
base.Update(frameTime);
var canFireSemi = _isFirstShot;
var state = _inputSystem.CmdStates.GetState(ContentKeyFunctions.Attack);
if (!_combatModeSystem.UseOrAttackIsDown && state != BoundKeyState.Down)
var state = _inputSystem.CmdStates.GetState(EngineKeyFunctions.Use);
if (!_combatModeSystem.IsInCombatMode() && state != BoundKeyState.Down)
{
_isFirstShot = true;
_blocked = false;

View File

@@ -15,7 +15,8 @@ namespace Content.Client.Input
common.AddFunction(ContentKeyFunctions.FocusChat);
common.AddFunction(ContentKeyFunctions.ExamineEntity);
common.AddFunction(ContentKeyFunctions.OpenTutorial);
common.AddFunction(ContentKeyFunctions.UseOrAttack);
common.AddFunction(ContentKeyFunctions.TakeScreenshot);
common.AddFunction(ContentKeyFunctions.TakeScreenshotNoUI);
var human = contexts.GetContext("human");
human.AddFunction(ContentKeyFunctions.SwapHands);
@@ -27,9 +28,11 @@ namespace Content.Client.Input
human.AddFunction(ContentKeyFunctions.OpenContextMenu);
human.AddFunction(ContentKeyFunctions.OpenCraftingMenu);
human.AddFunction(ContentKeyFunctions.OpenInventoryMenu);
human.AddFunction(ContentKeyFunctions.SmartEquipBackpack);
human.AddFunction(ContentKeyFunctions.SmartEquipBelt);
human.AddFunction(ContentKeyFunctions.MouseMiddle);
human.AddFunction(ContentKeyFunctions.ToggleCombatMode);
human.AddFunction(ContentKeyFunctions.Attack);
human.AddFunction(ContentKeyFunctions.WideAttack);
var ghost = contexts.New("ghost", "common");
ghost.AddFunction(EngineKeyFunctions.MoveUp);

View File

@@ -0,0 +1,85 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Content.Shared.Input;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Input;
using Robust.Shared.Input;
using Robust.Shared.Interfaces.Resources;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Utility;
using SixLabors.ImageSharp;
namespace Content.Client
{
internal class ScreenshotHook : IScreenshotHook
{
private static readonly ResourcePath BaseScreenshotPath = new ResourcePath("/Screenshots");
[Dependency] private readonly IInputManager _inputManager = default;
[Dependency] private readonly IClyde _clyde = default;
[Dependency] private readonly IResourceManager _resourceManager = default;
public void Initialize()
{
_inputManager.SetInputCommand(ContentKeyFunctions.TakeScreenshot, InputCmdHandler.FromDelegate(_ =>
{
Take(ScreenshotType.AfterUI);
}));
_inputManager.SetInputCommand(ContentKeyFunctions.TakeScreenshotNoUI, InputCmdHandler.FromDelegate(_ =>
{
Take(ScreenshotType.BeforeUI);
}));
}
private async void Take(ScreenshotType type)
{
var screenshot = await _clyde.ScreenshotAsync(type);
var time = DateTime.Now.ToString("yyyy-M-dd_HH.mm.ss");
if (!_resourceManager.UserData.IsDir(BaseScreenshotPath))
{
_resourceManager.UserData.CreateDir(BaseScreenshotPath);
}
for (var i = 0; i < 5; i++)
{
try
{
var filename = time;
if (i != 0)
{
filename = $"{filename}-{i}";
}
await using var file =
_resourceManager.UserData.Open(BaseScreenshotPath / $"{filename}.png", FileMode.CreateNew);
await Task.Run(() =>
{
// Saving takes forever, so don't hang the game on it.
screenshot.SaveAsPng(file);
});
Logger.InfoS("screenshot", "Screenshot taken as {0}.png", filename);
return;
}
catch (IOException e)
{
Logger.WarningS("screenshot", "Failed to save screenshot, retrying?:\n{0}", e);
}
}
Logger.ErrorS("screenshot", "Unable to save screenshot.");
}
}
public interface IScreenshotHook
{
void Initialize();
}
}

View File

@@ -21,6 +21,7 @@ namespace Content.Client.UserInterface.Stylesheets
public const string StyleClassLabelSecondaryColor = "LabelSecondaryColor";
public const string StyleClassLabelBig = "LabelBig";
public const string StyleClassButtonBig = "ButtonBig";
public const string StyleClassPopupMessage = "PopupMessage";
public static readonly Color NanoGold = Color.FromHex("#A88B5E");
@@ -41,6 +42,7 @@ namespace Content.Client.UserInterface.Stylesheets
public StyleNano(IResourceCache resCache) : base(resCache)
{
var notoSans10 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 10);
var notoSansItalic10 = resCache.GetFont("/Nano/NotoSans/NotoSans-Italic.ttf", 10);
var notoSans12 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 12);
var notoSansBold12 = resCache.GetFont("/Nano/NotoSans/NotoSans-Bold.ttf", 12);
var notoSansDisplayBold14 = resCache.GetFont("/Fonts/NotoSansDisplay/NotoSansDisplay-Bold.ttf", 14);
@@ -552,6 +554,14 @@ namespace Content.Client.UserInterface.Stylesheets
new StyleProperty("font", notoSans16)
}),
// Popup messages
new StyleRule(new SelectorElement(typeof(Label), new[] {StyleClassPopupMessage}, null, null),
new[]
{
new StyleProperty("font", notoSansItalic10),
new StyleProperty("font-color", Color.LightGray),
}),
//APC and SMES power state label colors
new StyleRule(new SelectorElement(typeof(Label), new[] {StyleClassPowerStateNone}, null, null), new[]
{

View File

@@ -69,10 +69,14 @@ namespace Content.Client.UserInterface
Switch hands: [color=#a4885c]{4}[/color]
Use held item: [color=#a4885c]{5}[/color]
Drop held item: [color=#a4885c]{6}[/color]
Smart equip from backpack: [color=#a4885c]{24}[/color]
Smart equip from belt: [color=#a4885c]{25}[/color]
Open inventory: [color=#a4885c]{7}[/color]
Open character window: [color=#a4885c]{8}[/color]
Open crafting window: [color=#a4885c]{9}[/color]
Focus chat: [color=#a4885c]{10}[/color]
Use hand/object in hand: [color=#a4885c]{22}[/color]
Do wide attack: [color=#a4885c]{23}[/color]
Use targeted entity: [color=#a4885c]{11}[/color]
Throw held item: [color=#a4885c]{12}[/color]
Examine entity: [color=#a4885c]{13}[/color]
@@ -102,16 +106,20 @@ Toggle sandbox window: [color=#a4885c]{21}[/color]",
Key(ShowDebugMonitors),
Key(OpenEntitySpawnWindow),
Key(OpenTileSpawnWindow),
Key(OpenSandboxWindow)));
//Gameplay
VBox.AddChild(new Label { FontOverride = headerFont, Text = Loc.GetString("\nSandbox spawner", Key(OpenSandboxWindow)) });
AddFormattedText(SandboxSpawnerContents);
Key(OpenSandboxWindow),
Key(Use),
Key(WideAttack),
Key(SmartEquipBackpack),
Key(SmartEquipBelt)));
//Gameplay
VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nGameplay" });
AddFormattedText(GameplayContents);
//Gameplay
VBox.AddChild(new Label { FontOverride = headerFont, Text = Loc.GetString("\nSandbox spawner", Key(OpenSandboxWindow)) });
AddFormattedText(SandboxSpawnerContents);
//Feedback
VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nFeedback" });
AddFormattedText(FeedbackContents);