2 Commits

Author SHA1 Message Date
clusterfack
609c718ca3 modify meshes 2018-06-27 22:51:32 -05:00
clusterfack
7e5acf8e45 3d branch 2018-06-25 02:08:40 -05:00
1194 changed files with 24739 additions and 33442 deletions

View File

@@ -1,24 +0,0 @@
version: 1.0.{build}
image: Visual Studio 2017
platform: x64
configuration: Debug
build:
project: SpaceStation.sln
parallel: false
verbosity: minimal
before_build:
- cmd: py -3 -m pip install --user requests
- cmd: py -3 RUN_THIS.py --no-prompt
- cmd: nuget restore SpaceStation14.sln
build_script:
- ps: msbuild SpaceStation14.sln /v:m /nologo /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /p:Platform=x64 /p:Configuration=Debug /p:AppVeyor=yes
test:
assemblies:
only:
- bin/Content.IntegrationTests/Content.IntegrationTests.dll
- bin/Content.Tests/Content.Tests.dll

2
.gitignore vendored
View File

@@ -268,8 +268,6 @@ release/
# Apple please go.
.DS_Store
# KDE, come in.
.directory
BuildFiles/Mac/Space Station 14.app/Contents/MacOS/Godot
BuildFiles/Mac/Space Station 14.app/Contents/MacOS/GodotSharpTools.dll

6
.gitmodules vendored
View File

@@ -1,4 +1,4 @@
[submodule "RobustToolbox"]
path = RobustToolbox
url = https://github.com/space-wizards/RobustToolbox.git
[submodule "engine"]
path = engine
url = https://github.com/space-wizards/space-station-14.git
branch = master

View File

@@ -9,30 +9,29 @@ os:
addons:
apt:
#sources:
#- deadsnakes
sources:
- deadsnakes
packages:
- python3.5
- python3-pip
- python3.6
cache:
directories:
- packages/
- RobustToolbox/Dependencies/
- RobustToolbox/SS14.Client.Godot/.mono/assemblies/
- engine/Dependencies/
- engine/SS14.Client.Godot/.mono/assemblies/
#before_install:
# - if [ $TRAVIS_OS_NAME = osx ]; then brew update && brew upgrade python; fi
before_script:
#- "if [ $TRAVIS_OS_NAME = linux ]; then pyenv shell 3.6; fi"
- "python3.5 -m pip install --user requests"
- "nuget restore SpaceStation14.sln"
- "python3.5 RUN_THIS.py --no-prompt"
- "if [ $TRAVIS_OS_NAME = linux ]; then pyenv shell 3.6; fi"
- "pip3 install --user requests"
- "nuget restore SpaceStation14Content.sln"
- "python3.6 RUN_THIS.py --no-prompt"
- "engine/Tools/download_godotsharp.py"
script:
- "msbuild /p:Configuration=Debug /p:Platform=x64 /nologo /m SpaceStation14.sln /p:Python=python3.5"
- "mono packages/nunit.consolerunner/3.10.0/tools/nunit3-console.exe bin/Content.Tests/Content.Tests.dll bin/Content.IntegrationTests/Content.IntegrationTests.dll"
- "msbuild /p:Configuration=Debug /p:Platform=x64 /p:HEADLESS=1 /p:Configuratio=Debug /nologo /m /p:AllowMissingMacNatives=yes SpaceStation14Content.sln /p:Python=python3.6"

View File

@@ -17,7 +17,7 @@ https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild
<Python>python3</Python>
<Python Condition="'$(OS)'=='Windows_NT' Or '$(OS)'=='Windows'">py -3</Python>
<ProjectGuid>{C899FCA4-7037-4E49-ABC2-44DE72487110}</ProjectGuid>
<TargetFrameworkMoniker>.NETFramework, Version=v4.7.1</TargetFrameworkMoniker>
<TargetFrameworkMoniker>.NETFramework, Version=v4.5.1</TargetFrameworkMoniker>
</PropertyGroup>
<PropertyGroup>
<OutputType>Library</OutputType>
@@ -25,9 +25,6 @@ https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<OutputPath>bin\Debug\</OutputPath>
</PropertyGroup>
<Target Name="Build">
<Exec Command="$(Python) git_helper.py" CustomErrorRegularExpression="^Error" />
</Target>

View File

@@ -8,7 +8,7 @@ import shutil
from pathlib import Path
from typing import List
SOLUTION_PATH = Path("..") / "SpaceStation14.sln"
SOLUTION_PATH = Path("..") / "SpaceStation14Content.sln"
# If this doesn't match the saved version we overwrite them all.
CURRENT_HOOKS_VERSION = "2"
QUIET = len(sys.argv) == 2 and sys.argv[1] == "--quiet"

View File

@@ -1,5 +0,0 @@
#!/bin/bash
cd "$(dirname "$0")"
exec mono bin/SS14.Launcher.exe

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>SS14L</string>
<key>CFBundleDisplayName</key>
<string>Space Station 14 Launcher</string>
<key>CFBundleExecutable</key>
<string>SS14</string>
<!--
Just a note about this icon.
MacOS seems REALLY iffy about this and even when the file is correct,
it can take forever before it decides to actually update it and display it.
TL;DR Apple is stupid.
-->
<key>CFBundleIconFile</key>
<string>ss14</string>
</dict>
</plist>

View File

@@ -1,8 +0,0 @@
#!/bin/sh
# cd to file containing script or something?
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
cd "$BASEDIR"
exec /Library/Frameworks/Mono.framework/Versions/Current/Commands/mono ../Resources/SS14.Launcher.exe

View File

@@ -1,8 +1,8 @@
#!/bin/sh
#!/usr/bin/env -i bash
# cd to file containing script or something?
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
cd "$BASEDIR"
exec /Library/Frameworks/Mono.framework/Versions/Current/Commands/mono ../Resources/Robust.Client.exe
./Godot --path ./SS14.Client.Godot

View File

@@ -0,0 +1 @@
call Godot\godot.windows.tools.64.mono.exe --path SS14.Client.Godot

View File

@@ -1 +0,0 @@
call bin\SS14.Launcher.exe

View File

@@ -1,73 +0,0 @@
using System;
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using Moq;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Benchmarks
{
public class ComponentManagerGetAllComponents
{
private readonly List<IEntity> _entities = new List<IEntity>();
private IComponentManager _componentManager;
[Params(500, 1000, 5000)] public int N { get; set; }
[GlobalSetup]
public void Setup()
{
// Initialize component manager.
IoCManager.InitThread();
IoCManager.Register<IComponentManager, ComponentManager>();
var dummyReg = new Mock<IComponentRegistration>();
dummyReg.SetupGet(p => p.Name).Returns("Dummy");
dummyReg.SetupGet(p => p.Type).Returns(typeof(DummyComponent));
dummyReg.SetupGet(p => p.NetID).Returns((uint?) null);
dummyReg.SetupGet(p => p.NetworkSynchronizeExistence).Returns(false);
dummyReg.SetupGet(p => p.References).Returns(new Type[] {typeof(DummyComponent)});
var componentFactory = new Mock<IComponentFactory>();
componentFactory.Setup(p => p.GetComponent<DummyComponent>()).Returns(new DummyComponent());
componentFactory.Setup(p => p.GetRegistration(It.IsAny<DummyComponent>())).Returns(dummyReg.Object);
IoCManager.RegisterInstance<IComponentFactory>(componentFactory.Object);
IoCManager.BuildGraph();
_componentManager = IoCManager.Resolve<IComponentManager>();
// Initialize N entities with one component.
for (var i = 0; i < N; i++)
{
var entity = new Entity();
entity.SetUid(new EntityUid(i + 1));
_entities.Add(entity);
_componentManager.AddComponent<DummyComponent>(entity);
}
}
[Benchmark]
public int Run()
{
var count = 0;
foreach (var _ in _componentManager.GetAllComponents<DummyComponent>())
{
count += 1;
}
return count;
}
private class DummyComponent : Component
{
public override string Name => "Dummy";
}
}
}

View File

@@ -1,25 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<OutputPath>..\bin\Content.Benchmarks\</OutputPath>
<IsPackable>false</IsPackable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<Platforms>x86;x64</Platforms>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Content.Client\Content.Client.csproj" />
<ProjectReference Include="..\Content.Server\Content.Server.csproj" />
<ProjectReference Include="..\Content.Shared\Content.Shared.csproj" />
<ProjectReference Include="..\Content.Tests\Content.Tests.csproj" />
<ProjectReference Include="..\Content.IntegrationTests\Content.IntegrationTests.csproj" />
<ProjectReference Include="..\RobustToolbox\Robust.Client\Robust.Client.csproj" />
<ProjectReference Include="..\RobustToolbox\Robust.Server\Robust.Server.csproj" />
<ProjectReference Include="..\RobustToolbox\Robust.Shared.Maths\Robust.Shared.Maths.csproj" />
<ProjectReference Include="..\RobustToolbox\Robust.Shared\Robust.Shared.csproj" />
<ProjectReference Include="..\RobustToolbox\Robust.UnitTesting\Robust.UnitTesting.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,13 +0,0 @@
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
namespace Content.Benchmarks
{
internal class Program
{
public static void Main(string[] args)
{
BenchmarkRunner.Run<ComponentManagerGetAllComponents>();
}
}
}

View File

@@ -1,232 +0,0 @@
using System.Collections.Generic;
using Content.Shared.Chat;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Input;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using Robust.Shared.Localization;
using Robust.Shared.IoC;
namespace Content.Client.Chat
{
public class ChatBox : MarginContainer
{
public delegate void TextSubmitHandler(ChatBox chatBox, string text);
public delegate void FilterToggledHandler(ChatBox chatBox, BaseButton.ButtonToggledEventArgs e);
private const int MaxLinePixelLength = 500;
private readonly IList<string> _inputHistory = new List<string>();
private ILocalizationManager localize = IoCManager.Resolve<ILocalizationManager>();
public LineEdit Input { get; private set; }
public OutputPanel contents;
// Buttons for filtering
public Button AllButton;
public Button LocalButton;
public Button OOCButton;
/// <summary>
/// Index while cycling through the input history. -1 means not going through history.
/// </summary>
private int _inputIndex = -1;
/// <summary>
/// Message that WAS being input before going through history began.
/// </summary>
private string _inputTemp;
/// <summary>
/// Default formatting string for the ClientChatConsole.
/// </summary>
public string DefaultChatFormat { get; set; }
public bool ReleaseFocusOnEnter { get; set; } = true;
protected override void Initialize()
{
base.Initialize();
MarginLeft = -475.0f;
MarginTop = 10.0f;
MarginRight = -10.0f;
MarginBottom = 235.0f;
AnchorLeft = 1.0f;
AnchorRight = 1.0f;
var outerVBox = new VBoxContainer();
var panelContainer = new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#25252aaa")},
SizeFlagsVertical = SizeFlags.FillExpand
};
var vBox = new VBoxContainer();
panelContainer.AddChild(vBox);
var hBox = new HBoxContainer();
outerVBox.AddChild(panelContainer);
outerVBox.AddChild(hBox);
var contentMargin = new MarginContainer
{
MarginLeftOverride = 4, MarginRightOverride = 4,
SizeFlagsVertical = SizeFlags.FillExpand
};
contents = new OutputPanel();
contentMargin.AddChild(contents);
vBox.AddChild(contentMargin);
Input = new LineEdit();
Input.OnKeyDown += InputKeyDown;
Input.OnTextEntered += Input_OnTextEntered;
vBox.AddChild(Input);
AllButton = new Button
{
Text = localize.GetString("All"),
Name = "ALL",
SizeFlagsHorizontal = SizeFlags.ShrinkEnd | SizeFlags.Expand,
ToggleMode = true,
};
LocalButton = new Button
{
Text = localize.GetString("Local"),
Name = "Local",
ToggleMode = true,
};
OOCButton = new Button
{
Text = localize.GetString("OOC"),
Name = "OOC",
ToggleMode = true,
};
AllButton.OnToggled += OnFilterToggled;
LocalButton.OnToggled += OnFilterToggled;
OOCButton.OnToggled += OnFilterToggled;
hBox.AddChild(AllButton);
hBox.AddChild(LocalButton);
hBox.AddChild(OOCButton);
AddChild(outerVBox);
}
protected override void MouseDown(GUIMouseButtonEventArgs e)
{
base.MouseDown(e);
Input.GrabKeyboardFocus();
}
private void InputKeyDown(GUIKeyEventArgs e)
{
if (e.Key == Keyboard.Key.Escape)
{
Input.ReleaseKeyboardFocus();
e.Handle();
return;
}
if (e.Key == Keyboard.Key.Up)
{
if (_inputIndex == -1 && _inputHistory.Count != 0)
{
_inputTemp = Input.Text;
_inputIndex++;
}
else if (_inputIndex + 1 < _inputHistory.Count)
{
_inputIndex++;
}
if (_inputIndex != -1)
{
Input.Text = _inputHistory[_inputIndex];
}
e.Handle();
return;
}
if (e.Key == Keyboard.Key.Down)
{
if (_inputIndex == 0)
{
Input.Text = _inputTemp;
_inputTemp = "";
_inputIndex--;
}
else if (_inputIndex != -1)
{
_inputIndex--;
Input.Text = _inputHistory[_inputIndex];
}
e.Handle();
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
TextSubmitted = null;
Input = null;
contents = null;
}
}
public event TextSubmitHandler TextSubmitted;
public event FilterToggledHandler FilterToggled;
public void AddLine(string message, ChatChannel channel, Color color)
{
if (Disposed)
{
return;
}
var formatted = new FormattedMessage(3);
formatted.PushColor(color);
formatted.AddText(message);
formatted.Pop();
contents.AddMessage(formatted);
}
private void Input_OnTextEntered(LineEdit.LineEditEventArgs args)
{
if (!string.IsNullOrWhiteSpace(args.Text))
{
TextSubmitted?.Invoke(this, args.Text);
_inputHistory.Insert(0, args.Text);
}
_inputIndex = -1;
Input.Clear();
if (ReleaseFocusOnEnter)
{
Input.ReleaseKeyboardFocus();
}
}
private void OnFilterToggled(BaseButton.ButtonToggledEventArgs args)
{
FilterToggled?.Invoke(this, args);
}
}
}

View File

@@ -1,408 +0,0 @@
using System.Collections.Generic;
using Content.Client.Interfaces.Chat;
using Content.Shared.Chat;
using Robust.Client;
using Robust.Client.Console;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
namespace Content.Client.Chat
{
internal sealed class ChatManager : IChatManager
{
/// <summary>
/// The max amount of chars allowed to fit in a single speech bubble.
/// </summary>
private const int SingleBubbleCharLimit = 100;
/// <summary>
/// Base queue delay each speech bubble has.
/// </summary>
private const float BubbleDelayBase = 0.2f;
/// <summary>
/// Factor multiplied by speech bubble char length to add to delay.
/// </summary>
private const float BubbleDelayFactor = 0.8f / SingleBubbleCharLimit;
/// <summary>
/// The max amount of speech bubbles over a single entity at once.
/// </summary>
private const int SpeechBubbleCap = 4;
private const char ConCmdSlash = '/';
private const char OOCAlias = '[';
private const char MeAlias = '@';
private readonly List<StoredChatMessage> filteredHistory = new List<StoredChatMessage>();
// Filter Button States
private bool _allState;
private bool _localState;
private bool _oocState;
// Flag Enums for holding filtered channels
private ChatChannel _filteredChannels;
#pragma warning disable 649
[Dependency] private readonly IClientNetManager _netManager;
[Dependency] private readonly IClientConsole _console;
[Dependency] private readonly IEntityManager _entityManager;
[Dependency] private readonly IEyeManager _eyeManager;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
#pragma warning restore 649
private ChatBox _currentChatBox;
private Control _speechBubbleRoot;
/// <summary>
/// Speech bubbles that are currently visible on screen.
/// We track them to push them up when new ones get added.
/// </summary>
private readonly Dictionary<EntityUid, List<SpeechBubble>> _activeSpeechBubbles =
new Dictionary<EntityUid, List<SpeechBubble>>();
/// <summary>
/// Speech bubbles that are to-be-sent because of the "rate limit" they have.
/// </summary>
private readonly Dictionary<EntityUid, SpeechBubbleQueueData> _queuedSpeechBubbles
= new Dictionary<EntityUid, SpeechBubbleQueueData>();
public void Initialize()
{
_netManager.RegisterNetMessage<MsgChatMessage>(MsgChatMessage.NAME, _onChatMessage);
_speechBubbleRoot = new Control();
_speechBubbleRoot.SetAnchorPreset(Control.LayoutPreset.Wide);
_userInterfaceManager.StateRoot.AddChild(_speechBubbleRoot);
_speechBubbleRoot.SetPositionFirst();
}
public void FrameUpdate(RenderFrameEventArgs delta)
{
// Update queued speech bubbles.
if (_queuedSpeechBubbles.Count == 0)
{
return;
}
foreach (var (entityUid, queueData) in _queuedSpeechBubbles.ShallowClone())
{
if (!_entityManager.TryGetEntity(entityUid, out var entity))
{
_queuedSpeechBubbles.Remove(entityUid);
continue;
}
queueData.TimeLeft -= delta.Elapsed;
if (queueData.TimeLeft > 0)
{
continue;
}
if (queueData.MessageQueue.Count == 0)
{
_queuedSpeechBubbles.Remove(entityUid);
continue;
}
var msg = queueData.MessageQueue.Dequeue();
queueData.TimeLeft += BubbleDelayBase + msg.Length * BubbleDelayFactor;
// We keep the queue around while it has 0 items. This allows us to keep the timer.
// When the timer hits 0 and there's no messages left, THEN we can clear it up.
CreateSpeechBubble(entity, msg);
}
}
public void SetChatBox(ChatBox chatBox)
{
if (_currentChatBox != null)
{
_currentChatBox.TextSubmitted -= _onChatBoxTextSubmitted;
_currentChatBox.FilterToggled -= _onFilterButtonToggled;
}
_currentChatBox = chatBox;
if (_currentChatBox != null)
{
_currentChatBox.TextSubmitted += _onChatBoxTextSubmitted;
_currentChatBox.FilterToggled += _onFilterButtonToggled;
}
RepopulateChat(filteredHistory);
_currentChatBox.AllButton.Pressed = !_allState;
_currentChatBox.LocalButton.Pressed = !_localState;
_currentChatBox.OOCButton.Pressed = !_oocState;
}
public void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble)
{
bubble.Dispose();
var list = _activeSpeechBubbles[entityUid];
list.Remove(bubble);
if (list.Count == 0)
{
_activeSpeechBubbles.Remove(entityUid);
}
}
private void WriteChatMessage(StoredChatMessage message)
{
Logger.Debug($"{message.Channel}: {message.Message}");
if (IsFiltered(message.Channel))
{
Logger.Debug($"Message filtered: {message.Channel}: {message.Message}");
return;
}
var color = Color.DarkGray;
var messageText = message.Message;
if (!string.IsNullOrEmpty(message.MessageWrap))
{
messageText = string.Format(message.MessageWrap, messageText);
}
switch (message.Channel)
{
case ChatChannel.Server:
color = Color.Orange;
break;
case ChatChannel.OOC:
color = Color.LightSkyBlue;
break;
}
_currentChatBox?.AddLine(messageText, message.Channel, color);
}
private void _onChatBoxTextSubmitted(ChatBox chatBox, string text)
{
DebugTools.Assert(chatBox == _currentChatBox);
if (string.IsNullOrWhiteSpace(text))
return;
switch (text[0])
{
case ConCmdSlash:
{
// run locally
var conInput = text.Substring(1);
_console.ProcessCommand(conInput);
break;
}
case OOCAlias:
{
var conInput = text.Substring(1);
_console.ProcessCommand($"ooc \"{conInput}\"");
break;
}
case MeAlias:
{
var conInput = text.Substring(1);
_console.ProcessCommand($"me \"{conInput}\"");
break;
}
default:
{
var conInput = _currentChatBox.DefaultChatFormat != null
? string.Format(_currentChatBox.DefaultChatFormat, text)
: text;
_console.ProcessCommand(conInput);
break;
}
}
}
private void _onFilterButtonToggled(ChatBox chatBox, BaseButton.ButtonToggledEventArgs e)
{
switch (e.Button.Name)
{
case "Local":
_localState = !_localState;
if (_localState)
{
_filteredChannels |= ChatChannel.Local;
break;
}
else
{
_filteredChannels &= ~ChatChannel.Local;
break;
}
case "OOC":
_oocState = !_oocState;
if (_oocState)
{
_filteredChannels |= ChatChannel.OOC;
break;
}
else
{
_filteredChannels &= ~ChatChannel.OOC;
break;
}
case "ALL":
chatBox.LocalButton.Pressed ^= true;
chatBox.OOCButton.Pressed ^= true;
_allState = !_allState;
break;
}
RepopulateChat(filteredHistory);
}
private void RepopulateChat(IEnumerable<StoredChatMessage> filteredMessages)
{
_currentChatBox.contents.Clear();
foreach (var msg in filteredMessages)
{
WriteChatMessage(msg);
}
}
private void _onChatMessage(MsgChatMessage msg)
{
Logger.Debug($"{msg.Channel}: {msg.Message}");
// Log all incoming chat to repopulate when filter is un-toggled
var storedMessage = new StoredChatMessage(msg);
filteredHistory.Add(storedMessage);
WriteChatMessage(storedMessage);
// Local messages that have an entity attached get a speech bubble.
if (msg.Channel == ChatChannel.Local && msg.SenderEntity != default)
{
AddSpeechBubble(msg);
}
}
private void AddSpeechBubble(MsgChatMessage msg)
{
if (!_entityManager.TryGetEntity(msg.SenderEntity, out var entity))
{
Logger.WarningS("chat", "Got local chat message with invalid sender entity: {0}", msg.SenderEntity);
return;
}
// Split message into words separated by spaces.
var words = msg.Message.Split(' ');
var messages = new List<string>();
var currentBuffer = new List<string>();
// Really shoddy way to approximate word length.
// Yes, I am aware of all the crimes here.
// TODO: Improve this to use actual glyph width etc..
var currentWordLength = 0;
foreach (var word in words)
{
// +1 for the space.
currentWordLength += word.Length + 1;
if (currentWordLength > SingleBubbleCharLimit)
{
// Too long for the current speech bubble, flush it.
messages.Add(string.Join(" ", currentBuffer));
currentBuffer.Clear();
currentWordLength = word.Length;
if (currentWordLength > SingleBubbleCharLimit)
{
// Word is STILL too long.
// Truncate it with an ellipse.
messages.Add($"{word.Substring(0, SingleBubbleCharLimit-3)}...");
currentWordLength = 0;
continue;
}
}
currentBuffer.Add(word);
}
if (currentBuffer.Count != 0)
{
// Don't forget the last bubble.
messages.Add(string.Join(" ", currentBuffer));
}
foreach (var message in messages)
{
EnqueueSpeechBubble(entity, message);
}
}
private void EnqueueSpeechBubble(IEntity entity, string contents)
{
if (!_queuedSpeechBubbles.TryGetValue(entity.Uid, out var queueData))
{
queueData = new SpeechBubbleQueueData();
_queuedSpeechBubbles.Add(entity.Uid, queueData);
}
queueData.MessageQueue.Enqueue(contents);
}
private void CreateSpeechBubble(IEntity entity, string contents)
{
var bubble = new SpeechBubble(contents, entity, _eyeManager, this);
if (_activeSpeechBubbles.TryGetValue(entity.Uid, out var existing))
{
// Push up existing bubbles above the mob's head.
foreach (var existingBubble in existing)
{
existingBubble.VerticalOffset += bubble.ContentHeight;
}
}
else
{
existing = new List<SpeechBubble>();
_activeSpeechBubbles.Add(entity.Uid, existing);
}
existing.Add(bubble);
_speechBubbleRoot.AddChild(bubble);
if (existing.Count > SpeechBubbleCap)
{
// Get the oldest to start fading fast.
var last = existing[0];
last.FadeNow();
}
}
private bool IsFiltered(ChatChannel channel)
{
// _allState works as inverter.
return _allState ^ _filteredChannels.HasFlag(channel);
}
private sealed class SpeechBubbleQueueData
{
/// <summary>
/// Time left until the next speech bubble can appear.
/// </summary>
public float TimeLeft { get; set; }
public Queue<string> MessageQueue { get; } = new Queue<string>();
}
}
}

View File

@@ -1,137 +0,0 @@
using Content.Client.Interfaces.Chat;
using Robust.Client;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Timers;
namespace Content.Client.Chat
{
public class SpeechBubble : Control
{
/// <summary>
/// The total time a speech bubble stays on screen.
/// </summary>
private const float TotalTime = 4;
/// <summary>
/// The amount of time at the end of the bubble's life at which it starts fading.
/// </summary>
private const float FadeTime = 0.25f;
/// <summary>
/// The distance in world space to offset the speech bubble from the center of the entity.
/// i.e. greater -> higher above the mob's head.
/// </summary>
private const float EntityVerticalOffset = 0.5f;
private readonly IEyeManager _eyeManager;
private readonly IEntity _senderEntity;
private readonly IChatManager _chatManager;
private Control _panel;
private float _timeLeft = TotalTime;
public float VerticalOffset { get; set; }
private float _verticalOffsetAchieved;
public float ContentHeight { get; }
public SpeechBubble(string text, IEntity senderEntity, IEyeManager eyeManager, IChatManager chatManager)
{
_chatManager = chatManager;
_senderEntity = senderEntity;
_eyeManager = eyeManager;
MouseFilter = MouseFilterMode.Ignore;
// Use text clipping so new messages don't overlap old ones being pushed up.
RectClipContent = true;
var label = new RichTextLabel
{
MaxWidth = 256,
MouseFilter = MouseFilterMode.Ignore
};
label.SetMessage(text);
_panel = new PanelContainer
{
StyleClasses = { "tooltipBox" },
Children = { label },
MouseFilter = MouseFilterMode.Ignore,
ModulateSelfOverride = Color.White.WithAlpha(0.75f)
};
AddChild(_panel);
_panel.Size = _panel.CombinedMinimumSize;
ContentHeight = _panel.Height;
Size = (_panel.Width, 0);
_verticalOffsetAchieved = -ContentHeight;
}
protected override void FrameUpdate(RenderFrameEventArgs args)
{
base.FrameUpdate(args);
_timeLeft -= args.Elapsed;
if (_timeLeft <= FadeTime)
{
// Update alpha if we're fading.
Modulate = Color.White.WithAlpha(_timeLeft / FadeTime);
}
if (_senderEntity.Deleted || _timeLeft <= 0)
{
// Timer spawn to prevent concurrent modification exception.
Timer.Spawn(0, Die);
return;
}
// Lerp to our new vertical offset if it's been modified.
if (FloatMath.CloseTo(_verticalOffsetAchieved - VerticalOffset, 0, 0.1))
{
_verticalOffsetAchieved = VerticalOffset;
}
else
{
_verticalOffsetAchieved = FloatMath.Lerp(_verticalOffsetAchieved, VerticalOffset, 10 * args.Elapsed);
}
var worldPos = _senderEntity.Transform.WorldPosition;
worldPos += (0, EntityVerticalOffset);
var lowerCenter = _eyeManager.WorldToScreen(worldPos) / UIScale;
var screenPos = lowerCenter - (Width / 2, ContentHeight + _verticalOffsetAchieved);
Position = screenPos;
var height = (lowerCenter.Y - screenPos.Y).Clamp(0, ContentHeight);
Size = (Size.X, height);
}
private void Die()
{
if (Disposed)
{
return;
}
_chatManager.RemoveSpeechBubble(_senderEntity.Uid, this);
}
/// <summary>
/// Causes the speech bubble to start fading IMMEDIATELY.
/// </summary>
public void FadeNow()
{
if (_timeLeft > FadeTime)
{
_timeLeft = FadeTime;
}
}
}
}

View File

@@ -1,38 +0,0 @@
using Content.Shared.Chat;
namespace Content.Client.Chat
{
public class StoredChatMessage
{
// TODO Make me reflected with respect to MsgChatMessage
/// <summary>
/// Client's own copies of chat messages used in filtering locally
/// </summary>
/// <summary>
/// Actual Message contents, i.e. words
/// </summary>
public string Message { get; set; }
/// <summary>
/// Message channel, used for filtering
/// </summary>
public ChatChannel Channel { get; set; }
/// <summary>
/// What to "wrap" the message contents with. Example is stuff like 'Joe says: "{0}"'
/// </summary>
public string MessageWrap { get; set; }
/// <summary>
/// Constructor to copy a net message into stored client variety
/// </summary>
public StoredChatMessage(MsgChatMessage netMsg)
{
Message = netMsg.Message;
Channel = netMsg.Channel;
MessageWrap = netMsg.MessageWrap;
}
}
}

View File

@@ -1,10 +0,0 @@
using System;
using Content.Shared;
namespace Content.Client
{
public sealed class ClientModuleTestingCallbacks : SharedModuleTestingCallbacks
{
public Action ClientBeforeIoC { get; set; }
}
}

View File

@@ -1,127 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Client.Interfaces;
using Content.Shared;
using Robust.Client;
using Robust.Client.Interfaces.Console;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
namespace Content.Client
{
public class ClientNotifyManager : SharedNotifyManager, IClientNotifyManager
{
#pragma warning disable 649
[Dependency] private IPlayerManager _playerManager;
[Dependency] private IUserInterfaceManager _userInterfaceManager;
[Dependency] private IInputManager _inputManager;
[Dependency] private IEyeManager _eyeManager;
[Dependency] private IClientNetManager _netManager;
#pragma warning restore 649
private readonly List<PopupLabel> _aliveLabels = new List<PopupLabel>();
private bool _initialized;
public void Initialize()
{
DebugTools.Assert(!_initialized);
_netManager.RegisterNetMessage<MsgDoNotify>(nameof(MsgDoNotify), DoNotifyMessage);
_initialized = true;
}
private void DoNotifyMessage(MsgDoNotify message)
{
PopupMessage(_eyeManager.WorldToScreen(message.Coordinates), message.Message);
}
public override void PopupMessage(GridCoordinates coordinates, IEntity viewer, string message)
{
if (viewer != _playerManager.LocalPlayer.ControlledEntity)
{
return;
}
PopupMessage(_eyeManager.WorldToScreen(coordinates), message);
}
public void PopupMessage(ScreenCoordinates coordinates, string message)
{
var label = new PopupLabel {Text = message};
var minimumSize = label.CombinedMinimumSize;
label.InitialPos = label.Position = coordinates.Position - minimumSize / 2;
_userInterfaceManager.StateRoot.AddChild(label);
_aliveLabels.Add(label);
}
public void PopupMessage(string message)
{
PopupMessage(new ScreenCoordinates(_inputManager.MouseScreenPosition), message);
}
public void FrameUpdate(RenderFrameEventArgs eventArgs)
{
foreach (var label in _aliveLabels)
{
label.Update(eventArgs);
}
_aliveLabels.RemoveAll(l => l.Disposed);
}
private class PopupLabel : Label
{
private float _timeLeft;
public Vector2 InitialPos { get; set; }
protected override void Initialize()
{
base.Initialize();
ShadowOffsetXOverride = 1;
ShadowOffsetYOverride = 1;
FontColorShadowOverride = Color.Black;
}
public void Update(RenderFrameEventArgs eventArgs)
{
_timeLeft += eventArgs.Elapsed;
Position = InitialPos - new Vector2(0, 20 * (_timeLeft * _timeLeft + _timeLeft));
if (_timeLeft > 0.5f)
{
Modulate = Color.White.WithAlpha(1f - 0.2f * (float)Math.Pow(_timeLeft - 0.5f, 3f));
if (_timeLeft > 3f)
{
Dispose();
}
}
}
}
}
public class PopupMessageCommand : IConsoleCommand
{
public string Command => "popupmsg";
public string Description => "";
public string Help => "";
public bool Execute(IDebugConsole console, params string[] args)
{
var arg = args[0];
var mgr = IoCManager.Resolve<IClientNotifyManager>();
mgr.PopupMessage(arg);
return false;
}
}
}

View File

@@ -1,57 +0,0 @@
using Content.Client.Interfaces;
using Content.Shared.GameObjects.Components.Markers;
using Robust.Client.Interfaces.Console;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Client.Commands
{
internal sealed class ShowMarkersCommand : IConsoleCommand
{
// ReSharper disable once StringLiteralTypo
public string Command => "togglemarkers";
public string Description => "Toggles visibility of markers such as spawn points.";
public string Help => "";
public bool Execute(IDebugConsole console, params string[] args)
{
bool? whichToSet = null;
foreach (var entity in IoCManager.Resolve<IEntityManager>()
.GetEntities(new TypeEntityQuery(typeof(SharedSpawnPointComponent))))
{
if (!entity.TryGetComponent(out ISpriteComponent sprite))
{
continue;
}
if (!whichToSet.HasValue)
{
whichToSet = !sprite.Visible;
}
sprite.Visible = whichToSet.Value;
}
return false;
}
}
internal sealed class NotifyCommand : IConsoleCommand
{
public string Command => "notify";
public string Description => "Send a notify client side.";
public string Help => "notify <message>";
public bool Execute(IDebugConsole console, params string[] args)
{
var message = args[0];
var notifyManager = IoCManager.Resolve<IClientNotifyManager>();
notifyManager.PopupMessage(message);
return false;
}
}
}

View File

@@ -1,391 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Content.Client.GameObjects.Components.Construction;
using Content.Shared.Construction;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Interfaces.GameObjects;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Placement;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Placement;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.Utility;
using Robust.Shared.Enums;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.Construction
{
public class ConstructionMenu : SS14Window
{
#pragma warning disable CS0649
[Dependency]
readonly IPrototypeManager PrototypeManager;
[Dependency]
readonly IResourceCache ResourceCache;
#pragma warning restore
public ConstructorComponent Owner { get; set; }
Button BuildButton;
Button EraseButton;
LineEdit SearchBar;
Tree RecipeList;
TextureRect InfoIcon;
Label InfoLabel;
ItemList StepList;
CategoryNode RootCategory;
// This list is flattened in such a way that the top most deepest category is first.
List<CategoryNode> FlattenedCategories;
PlacementManager Placement;
public ConstructionMenu()
{
Size = new Vector2(500.0f, 350.0f);
}
protected override void Initialize()
{
base.Initialize();
IoCManager.InjectDependencies(this);
Placement = (PlacementManager)IoCManager.Resolve<IPlacementManager>();
Placement.PlacementCanceled += OnPlacementCanceled;
Title = "Construction";
var hSplitContainer = new HSplitContainer();
// Left side
var recipes = new VBoxContainer("Recipes") {CustomMinimumSize = new Vector2(150.0f, 0.0f)};
SearchBar = new LineEdit("Search") {PlaceHolder = "Search"};
RecipeList = new Tree("Tree") {SizeFlagsVertical = SizeFlags.FillExpand, HideRoot = true};
recipes.AddChild(SearchBar);
recipes.AddChild(RecipeList);
hSplitContainer.AddChild(recipes);
// Right side
var guide = new VBoxContainer("Guide");
var info = new HBoxContainer("Info");
InfoIcon = new TextureRect("TextureRect");
InfoLabel = new Label("Label")
{
SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsVertical = SizeFlags.ShrinkCenter
};
info.AddChild(InfoIcon);
info.AddChild(InfoLabel);
guide.AddChild(info);
var stepsLabel = new Label("Label")
{
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
SizeFlagsVertical = SizeFlags.ShrinkCenter,
Text = "Steps"
};
guide.AddChild(stepsLabel);
StepList = new ItemList("StepsList")
{
SizeFlagsVertical = SizeFlags.FillExpand, SelectMode = ItemList.ItemListSelectMode.None
};
guide.AddChild(StepList);
var buttonsContainer = new HBoxContainer("Buttons");
BuildButton = new Button("BuildButton")
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
TextAlign = Button.AlignMode.Center,
Text = "Build!",
Disabled = true,
ToggleMode = false
};
EraseButton = new Button("EraseButton")
{
TextAlign = Button.AlignMode.Center, Text = "Clear Ghosts", ToggleMode = true
};
buttonsContainer.AddChild(BuildButton);
buttonsContainer.AddChild(EraseButton);
guide.AddChild(buttonsContainer);
hSplitContainer.AddChild(guide);
Contents.AddChild(hSplitContainer);
BuildButton.OnPressed += OnBuildPressed;
EraseButton.OnToggled += OnEraseToggled;
SearchBar.OnTextChanged += OnTextEntered;
RecipeList.OnItemSelected += OnItemSelected;
PopulatePrototypeList();
PopulateTree();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
Placement.PlacementCanceled -= OnPlacementCanceled;
}
}
void OnItemSelected()
{
var prototype = (ConstructionPrototype)RecipeList.Selected.Metadata;
if (prototype == null)
{
InfoLabel.Text = "";
InfoIcon.Texture = null;
StepList.Clear();
BuildButton.Disabled = true;
}
else
{
BuildButton.Disabled = false;
InfoLabel.Text = prototype.Description;
InfoIcon.Texture = prototype.Icon.Frame0();
StepList.Clear();
foreach (var forward in prototype.Stages.Select(a => a.Forward))
{
if (forward == null)
{
continue;
}
Texture icon;
string text;
switch (forward)
{
case ConstructionStepMaterial mat:
switch (mat.Material)
{
case ConstructionStepMaterial.MaterialType.Metal:
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/sheet_metal.png");
text = $"Metal x{mat.Amount}";
break;
case ConstructionStepMaterial.MaterialType.Glass:
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/sheet_glass.png");
text = $"Glass x{mat.Amount}";
break;
case ConstructionStepMaterial.MaterialType.Cable:
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/cable_coil.png");
text = $"Cable Coil x{mat.Amount}";
break;
default:
throw new NotImplementedException();
}
break;
case ConstructionStepTool tool:
switch (tool.Tool)
{
case ConstructionStepTool.ToolType.Wrench:
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/wrench.png");
text = "Wrench";
break;
case ConstructionStepTool.ToolType.Crowbar:
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/crowbar.png");
text = "Crowbar";
break;
case ConstructionStepTool.ToolType.Screwdriver:
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/screwdriver.png");
text = "Screwdriver";
break;
case ConstructionStepTool.ToolType.Welder:
icon = ResourceCache.GetResource<RSIResource>("/Textures/Objects/tools.rsi").RSI["welder"].Frame0;
text = $"Welding tool ({tool.Amount} fuel)";
break;
case ConstructionStepTool.ToolType.Wirecutters:
icon = ResourceCache.GetResource<TextureResource>("/Textures/Objects/wirecutter.png");
text = "Wirecutters";
break;
default:
throw new NotImplementedException();
}
break;
default:
throw new NotImplementedException();
}
StepList.AddItem(text, icon, false);
}
}
}
void OnTextEntered(LineEdit.LineEditEventArgs args)
{
var str = args.Text;
PopulateTree(string.IsNullOrWhiteSpace(str) ? null : str.ToLowerInvariant());
}
void OnBuildPressed(Button.ButtonEventArgs args)
{
var prototype = (ConstructionPrototype)RecipeList.Selected.Metadata;
if (prototype == null)
{
return;
}
if (prototype.Type != ConstructionType.Structure)
{
// In-hand attackby doesn't exist so this is the best alternative.
var loc = Owner.Owner.GetComponent<ITransformComponent>().GridPosition;
Owner.SpawnGhost(prototype, loc, Direction.North);
return;
}
var hijack = new ConstructionPlacementHijack(prototype, Owner);
var info = new PlacementInformation
{
IsTile = false,
PlacementOption = prototype.PlacementMode,
};
Placement.BeginHijackedPlacing(info, hijack);
}
private void OnEraseToggled(BaseButton.ButtonToggledEventArgs args)
{
var hijack = new ConstructionPlacementHijack(null, Owner);
Placement.ToggleEraserHijacked(hijack);
}
void PopulatePrototypeList()
{
RootCategory = new CategoryNode("", null);
int count = 1;
foreach (var prototype in PrototypeManager.EnumeratePrototypes<ConstructionPrototype>())
{
var currentNode = RootCategory;
foreach (var category in prototype.CategorySegments)
{
if (!currentNode.ChildCategories.TryGetValue(category, out var subNode))
{
count++;
subNode = new CategoryNode(category, currentNode);
currentNode.ChildCategories.Add(category, subNode);
}
currentNode = subNode;
}
currentNode.Prototypes.Add(prototype);
}
// Do a pass to sort the prototype lists and flatten the hierarchy.
void Recurse(CategoryNode node)
{
// I give up we're using recursion to flatten this.
// There probably IS a way to do it.
// I'm too stupid to think of what that way is.
foreach (var child in node.ChildCategories.Values)
{
Recurse(child);
}
node.Prototypes.Sort(ComparePrototype);
FlattenedCategories.Add(node);
node.FlattenedIndex = FlattenedCategories.Count - 1;
}
FlattenedCategories = new List<CategoryNode>(count);
Recurse(RootCategory);
}
void PopulateTree(string searchTerm = null)
{
RecipeList.Clear();
var categoryItems = new Tree.Item[FlattenedCategories.Count];
categoryItems[RootCategory.FlattenedIndex] = RecipeList.CreateItem();
// Yay more recursion.
Tree.Item ItemForNode(CategoryNode node)
{
if (categoryItems[node.FlattenedIndex] != null)
{
return categoryItems[node.FlattenedIndex];
}
var item = RecipeList.CreateItem(ItemForNode(node.Parent));
item.Text = node.Name;
item.Selectable = false;
categoryItems[node.FlattenedIndex] = item;
return item;
}
foreach (var node in FlattenedCategories)
{
foreach (var prototype in node.Prototypes)
{
if (searchTerm != null)
{
var found = false;
// TODO: don't run ToLowerInvariant() constantly.
if (prototype.Name.ToLowerInvariant().IndexOf(searchTerm) != -1)
{
found = true;
}
else
{
foreach (var keyw in prototype.Keywords.Concat(prototype.CategorySegments))
{
// TODO: don't run ToLowerInvariant() constantly.
if (keyw.ToLowerInvariant().IndexOf(searchTerm) != -1)
{
found = true;
break;
}
}
}
if (!found)
{
continue;
}
}
var subItem = RecipeList.CreateItem(ItemForNode(node));
subItem.Text = prototype.Name;
subItem.Metadata = prototype;
}
}
}
private void OnPlacementCanceled(object sender, EventArgs e)
{
EraseButton.Pressed = false;
}
private static int ComparePrototype(ConstructionPrototype x, ConstructionPrototype y)
{
return x.Name.CompareTo(y.Name);
}
class CategoryNode
{
public readonly string Name;
public readonly CategoryNode Parent;
public SortedDictionary<string, CategoryNode> ChildCategories = new SortedDictionary<string, CategoryNode>();
public List<ConstructionPrototype> Prototypes = new List<ConstructionPrototype>();
public int FlattenedIndex = -1;
public CategoryNode(string name, CategoryNode parent)
{
Name = name;
Parent = parent;
}
}
}
}

View File

@@ -1,53 +0,0 @@
using Content.Client.GameObjects.Components.Construction;
using Content.Shared.Construction;
using Robust.Client.Graphics;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Placement;
using Robust.Client.ResourceManagement;
using Robust.Client.Utility;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
namespace Content.Client.Construction
{
public class ConstructionPlacementHijack : PlacementHijack
{
private readonly ConstructionPrototype Prototype;
private readonly ConstructorComponent Owner;
public ConstructionPlacementHijack(ConstructionPrototype prototype, ConstructorComponent owner)
{
Prototype = prototype;
Owner = owner;
}
public override bool HijackPlacementRequest(GridCoordinates coords)
{
if (Prototype != null)
{
var dir = Manager.Direction;
Owner.SpawnGhost(Prototype, coords, dir);
}
return true;
}
public override bool HijackDeletion(IEntity entity)
{
if (entity.TryGetComponent(out ConstructionGhostComponent ghost))
{
Owner.ClearGhost(ghost.GhostID);
}
return true;
}
public override void StartHijack(PlacementManager manager)
{
base.StartHijack(manager);
var res = IoCManager.Resolve<IResourceCache>();
manager.CurrentBaseSprite = Prototype.Icon.DirFrame0();
}
}
}

View File

@@ -1,27 +1,112 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<LangVersion>7.3</LangVersion>
<IsPackable>false</IsPackable>
<Platforms>x64;x86</Platforms>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
<ProjectGuid>{A2E5F175-78AF-4DDD-8F97-E2D2552372ED}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Content.Client</RootNamespace>
<AssemblyName>Content.Client</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ContentAssemblyTarget>..\engine\bin\Client\Resources\Assemblies\</ContentAssemblyTarget>
<!--
This copies all dependencies,
but on the plus side it's automatically located in the right place.
-->
<OutputPath>..\bin\Content.Client\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet Condition="'$(ActualOS)' == 'Windows'">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>portable</DebugType>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<DefineConstants>TRACE;RELEASE</DefineConstants>
<Optimize>true</Optimize>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>portable</DebugType>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<DefineConstants>TRACE;RELEASE</DefineConstants>
<Optimize>true</Optimize>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DefineConstants>TRACE;RELEASE</DefineConstants>
<Optimize>true</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>portable</DebugType>
</PropertyGroup>
<Import Project="..\RobustToolbox\MSBuild\Robust.DefineConstants.targets" />
<ItemGroup>
<PackageReference Include="Nett" Version="0.11.0" />
<PackageReference Include="SixLabors.Core" Version="1.0.0-beta0007" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0006" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="YamlDotNet" Version="6.0.0" />
<PackageReference Include="SharpZipLib" Version="1.1.0" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)packages\OpenTK.3.0.0-pre\lib\net20\OpenTK.dll</HintPath>
</Reference>
<Reference Include="YamlDotNet, Version=4.3.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)packages\YamlDotNet.4.3.1\lib\net45\YamlDotNet.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RobustToolbox\Lidgren.Network\Lidgren.Network.csproj" />
<ProjectReference Include="..\RobustToolbox\Robust.Shared.Maths\Robust.Shared.Maths.csproj" />
<ProjectReference Include="..\RobustToolbox\Robust.Shared\Robust.Shared.csproj" />
<ProjectReference Include="..\RobustToolbox\Robust.Client\Robust.Client.csproj" />
<ProjectReference Include="..\Content.Shared\Content.Shared.csproj" />
<Compile Include="EntryPoint.cs" />
<Compile Include="GameObjects\Components\Inventory\ClientInventoryComponent.cs" />
<Compile Include="GameObjects\Components\Storage\ClientStorageComponent.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="GameObjects\Components\Items\ClientHandsComponent.cs" />
<Compile Include="Interfaces\GameObjects\Components\Items\IHandsComponent.cs" />
<Compile Include="UserInterface\HandsGui.cs" />
<Compile Include="GameObjects\Components\Power\PowerDebugTool.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Content.Shared\Content.Shared.csproj">
<Project>{26aeebb3-dde7-443a-9f43-7bc7f4acf6b5}</Project>
<Name>Content.Shared</Name>
</ProjectReference>
<ProjectReference Include="..\engine\Lidgren.Network\Lidgren.Network.csproj">
<Project>{59250baf-0000-0000-0000-000000000000}</Project>
<Name>Lidgren.Network</Name>
</ProjectReference>
<ProjectReference Include="..\engine\SS14.Client\SS14.Client.csproj">
<Project>{83429BD6-6358-4B18-BE51-401DF8EA2673}</Project>
<Name>SS14.Client</Name>
</ProjectReference>
<ProjectReference Include="..\engine\SS14.Shared\SS14.Shared.csproj">
<Project>{0529f740-0000-0000-0000-000000000000}</Project>
<Name>SS14.Shared</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\SS14.Content.targets" />
<Target Name="AfterBuild" DependsOnTargets="CopyContentAssemblies" />
<ItemGroup>
<!-- Files to be copied into Client/Assemblies -->
<ContentAssemblies Include="$(OutputPath)Content.Client.dll" />
<ContentAssemblies Include="$(OutputPath)Content.Shared.dll" />
<ContentAssemblies Include="$(OutputPath)Content.Client.pdb" Condition="'$(Configuration)' == 'Debug'" />
<ContentAssemblies Include="$(OutputPath)Content.Shared.pdb" Condition="'$(Configuration)' == 'Debug'" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
</Project>

View File

@@ -1,194 +1,50 @@
using System;
using Content.Client.Chat;
using Content.Client.GameObjects.Components.Actor;
using Content.Client.GameTicking;
using Content.Client.Input;
using Content.Client.Interfaces;
using Content.Client.Interfaces.Chat;
using Content.Client.Interfaces.Parallax;
using Content.Client.Parallax;
using Content.Client.UserInterface;
using Content.Shared.GameObjects.Components.Chemistry;
using Content.Shared.GameObjects.Components.Markers;
using Content.Shared.GameObjects.Components.Research;
using Content.Shared.Interfaces;
using Robust.Client;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
using Robust.Shared.ContentPack;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Content.Client.GameObjects;
using Content.Client.GameObjects.Components.Power;
using Content.Client.GameObjects.Components.Storage;
using Content.Client.Interfaces.GameObjects;
using SS14.Shared.ContentPack;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.IoC;
namespace Content.Client
{
public class EntryPoint : GameClient
{
#pragma warning disable 649
[Dependency] private readonly IPlayerManager _playerManager;
[Dependency] private readonly IEscapeMenuOwner _escapeMenuOwner;
#pragma warning restore 649
public override void Init()
{
var factory = IoCManager.Resolve<IComponentFactory>();
var prototypes = IoCManager.Resolve<IPrototypeManager>();
factory.DoAutoRegistrations();
factory.RegisterIgnore("Item");
factory.RegisterIgnore("Interactable");
factory.RegisterIgnore("Damageable");
factory.RegisterIgnore("Destructible");
factory.RegisterIgnore("Temperature");
factory.RegisterIgnore("PowerTransfer");
factory.RegisterIgnore("PowerNode");
factory.RegisterIgnore("PowerProvider");
factory.RegisterIgnore("PowerDevice");
factory.RegisterIgnore("PowerStorage");
factory.RegisterIgnore("PowerGenerator");
var registerIgnore = new[]
{
"Interactable",
"Destructible",
"Temperature",
"PowerTransfer",
"PowerNode",
"PowerProvider",
"PowerDevice",
"PowerStorage",
"PowerGenerator",
"Explosive",
"OnUseTimerTrigger",
"ToolboxElectricalFill",
"ToolLockerFill",
"EmitSoundOnUse",
"FootstepModifier",
"HeatResistance",
"CombatMode",
"Teleportable",
"ItemTeleporter",
"Portal",
"EntityStorage",
"PlaceableSurface",
"Wirecutter",
"Screwdriver",
"Multitool",
"Welder",
"Wrench",
"Crowbar",
"HitscanWeapon",
"ProjectileWeapon",
"Projectile",
"MeleeWeapon",
"Storeable",
"Stack",
"Dice",
"Construction",
"Apc",
"Door",
"PoweredLight",
"Smes",
"Powercell",
"HandheldLight",
"LightBulb",
"Healing",
"Catwalk",
"BallisticMagazine",
"BallisticMagazineWeapon",
"BallisticBullet",
"HitscanWeaponCapacitor",
"PowerCell",
"AiController",
"PlayerInputMover",
};
factory.RegisterIgnore("Wirecutter");
factory.RegisterIgnore("Screwdriver");
factory.RegisterIgnore("Multitool");
factory.RegisterIgnore("Welder");
factory.RegisterIgnore("Wrench");
factory.RegisterIgnore("Crowbar");
factory.RegisterIgnore("HitscanWeapon");
factory.RegisterIgnore("ProjectileWeapon");
factory.RegisterIgnore("Projectile");
factory.RegisterIgnore("MeleeWeapon");
foreach (var ignoreName in registerIgnore)
{
factory.RegisterIgnore(ignoreName);
}
factory.RegisterIgnore("Storeable");
factory.RegisterIgnore("Clothing");
factory.Register<SharedLatheComponent>();
factory.Register<SharedSpawnPointComponent>();
factory.Register<SolutionComponent>();
prototypes.RegisterIgnore("material");
IoCManager.Register<IGameHud, GameHud>();
IoCManager.Register<IClientNotifyManager, ClientNotifyManager>();
IoCManager.Register<ISharedNotifyManager, ClientNotifyManager>();
IoCManager.Register<IClientGameTicker, ClientGameTicker>();
IoCManager.Register<IParallaxManager, ParallaxManager>();
IoCManager.Register<IChatManager, ChatManager>();
IoCManager.Register<IEscapeMenuOwner, EscapeMenuOwner>();
if (TestingCallbacks != null)
{
var cast = (ClientModuleTestingCallbacks) TestingCallbacks;
cast.ClientBeforeIoC?.Invoke();
}
IoCManager.BuildGraph();
IoCManager.Resolve<IParallaxManager>().LoadParallax();
IoCManager.Resolve<IBaseClient>().PlayerJoinedServer += SubscribePlayerAttachmentEvents;
var stylesheet = new NanoStyle();
IoCManager.Resolve<IUserInterfaceManager>().Stylesheet = stylesheet.Stylesheet;
IoCManager.Resolve<IUserInterfaceManager>().Stylesheet = stylesheet.Stylesheet;
IoCManager.InjectDependencies(this);
_escapeMenuOwner.Initialize();
}
/// <summary>
/// Subscribe events to the player manager after the player manager is set up
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void SubscribePlayerAttachmentEvents(object sender, EventArgs args)
{
_playerManager.LocalPlayer.EntityAttached += AttachPlayerToEntity;
_playerManager.LocalPlayer.EntityDetached += DetachPlayerFromEntity;
}
/// <summary>
/// Add the character interface master which combines all character interfaces into one window
/// </summary>
public static void AttachPlayerToEntity(EntityAttachedEventArgs eventArgs)
{
eventArgs.NewEntity.AddComponent<CharacterInterface>();
}
/// <summary>
/// Remove the character interface master from this entity now that we have detached ourselves from it
/// </summary>
public static void DetachPlayerFromEntity(EntityDetachedEventArgs eventArgs)
{
eventArgs.OldEntity.RemoveComponent<CharacterInterface>();
}
public override void PostInit()
{
base.PostInit();
// Setup key contexts
var inputMan = IoCManager.Resolve<IInputManager>();
ContentContexts.SetupContexts(inputMan.Contexts);
IoCManager.Resolve<IGameHud>().Initialize();
IoCManager.Resolve<IClientNotifyManager>().Initialize();
IoCManager.Resolve<IClientGameTicker>().Initialize();
IoCManager.Resolve<IOverlayManager>().AddOverlay(new ParallaxOverlay());
IoCManager.Resolve<IChatManager>().Initialize();
}
public override void Update(ModUpdateLevel level, float frameTime)
{
base.Update(level, frameTime);
switch (level)
{
case ModUpdateLevel.FramePreEngine:
var renderFrameEventArgs = new RenderFrameEventArgs(frameTime);
IoCManager.Resolve<IClientNotifyManager>().FrameUpdate(renderFrameEventArgs);
IoCManager.Resolve<IClientGameTicker>().FrameUpdate(renderFrameEventArgs);
IoCManager.Resolve<IChatManager>().FrameUpdate(renderFrameEventArgs);
break;
}
factory.Register<HandsComponent>();
factory.RegisterReference<HandsComponent, IHandsComponent>();
factory.Register<ClientStorageComponent>();
factory.Register<ClientInventoryComponent>();
factory.Register<PowerDebugTool>();
}
}
}

View File

@@ -1,104 +0,0 @@
using Content.Client.UserInterface;
using Robust.Client.Console;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.Placement;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.State;
using Robust.Client.State.States;
using Robust.Shared.Input;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Players;
using Robust.Shared.Prototypes;
namespace Content.Client
{
internal sealed class EscapeMenuOwner : IEscapeMenuOwner
{
#pragma warning disable 649
[Dependency] private readonly IClientConsole _clientConsole;
[Dependency] private readonly IConfigurationManager _configurationManager;
[Dependency] private readonly IInputManager _inputManager;
[Dependency] private readonly IPlacementManager _placementManager;
[Dependency] private readonly IPrototypeManager _prototypeManager;
[Dependency] private readonly IResourceCache _resourceCache;
[Dependency] private readonly IStateManager _stateManager;
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager;
[Dependency] private readonly IGameHud _gameHud;
[Dependency] private readonly ILocalizationManager _localizationManager;
#pragma warning restore 649
private EscapeMenu _escapeMenu;
public void Initialize()
{
_stateManager.OnStateChanged += StateManagerOnOnStateChanged;
_gameHud.EscapeButtonToggled += _setOpenValue;
}
private void StateManagerOnOnStateChanged(StateChangedEventArgs obj)
{
if (obj.NewState is GameScreen)
{
// Switched TO GameScreen.
_escapeMenu = new EscapeMenu(_clientConsole, _tileDefinitionManager, _placementManager,
_prototypeManager, _resourceCache, _configurationManager, _localizationManager);
_escapeMenu.OnClose += () => _gameHud.EscapeButtonDown = false;
var escapeMenuCommand = InputCmdHandler.FromDelegate(Enabled);
_inputManager.SetInputCommand(EngineKeyFunctions.EscapeMenu, escapeMenuCommand);
}
else if (obj.OldState is GameScreen)
{
// Switched FROM GameScreen.
_escapeMenu.Dispose();
_escapeMenu = null;
_inputManager.SetInputCommand(EngineKeyFunctions.EscapeMenu, null);
}
}
private void Enabled(ICommonSession session)
{
if (_escapeMenu.IsOpen)
{
if (_escapeMenu.IsAtFront())
{
_setOpenValue(false);
}
else
{
_escapeMenu.MoveToFront();
}
}
else
{
_setOpenValue(true);
}
}
private void _setOpenValue(bool value)
{
if (value)
{
_gameHud.EscapeButtonDown = true;
_escapeMenu.OpenCentered();
}
else
{
_gameHud.EscapeButtonDown = false;
_escapeMenu.Close();
}
}
}
public interface IEscapeMenuOwner
{
void Initialize();
}
}

View File

@@ -1,95 +0,0 @@
using Content.Client.GameObjects.Components.Mobs;
using Content.Client.UserInterface;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
namespace Content.Client.GameObjects.Components.Actor
{
[RegisterComponent]
public sealed class CharacterInfoComponent : Component, ICharacterUI
{
private CharacterInfoControl _control;
#pragma warning disable 649
[Dependency] private readonly ILocalizationManager _loc;
[Dependency] private readonly IResourceCache _resourceCache;
#pragma warning restore 649
public override string Name => "CharacterInfo";
public Control Scene { get; private set; }
public UIPriority Priority => UIPriority.Info;
public override void OnAdd()
{
base.OnAdd();
Scene = _control = new CharacterInfoControl(_resourceCache, _loc);
}
public override void Initialize()
{
base.Initialize();
if (Owner.TryGetComponent(out ISpriteComponent spriteComponent))
{
_control.SpriteView.Sprite = spriteComponent;
}
_control.NameLabel.Text = Owner.Name;
// ReSharper disable once StringLiteralTypo
_control.SubText.Text = _loc.GetString("Professional Greyshirt");
}
private sealed class CharacterInfoControl : VBoxContainer
{
public SpriteView SpriteView { get; }
public Label NameLabel { get; }
public Label SubText { get; }
public CharacterInfoControl(IResourceCache resourceCache, ILocalizationManager loc)
{
AddChild(new HBoxContainer
{
Children =
{
(SpriteView = new SpriteView { Scale = (2, 2)}),
new VBoxContainer
{
SizeFlagsVertical = SizeFlags.None,
Children =
{
(NameLabel = new Label()),
(SubText = new Label
{
SizeFlagsVertical = SizeFlags.None,
StyleClasses = {NanoStyle.StyleClassLabelSubText}
})
}
}
}
});
AddChild(new Placeholder(resourceCache)
{
PlaceholderText = loc.GetString("Health & status effects")
});
AddChild(new Placeholder(resourceCache)
{
PlaceholderText = loc.GetString("Objectives")
});
AddChild(new Placeholder(resourceCache)
{
PlaceholderText = loc.GetString("Antagonist Roles")
});
}
}
}
}

View File

@@ -1,143 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Content.Client.GameObjects.Components.Mobs;
using Content.Client.UserInterface;
using Content.Shared.Input;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.Input;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
namespace Content.Client.GameObjects.Components.Actor
{
/// <summary>
/// A semi-abstract component which gets added to entities upon attachment and collects all character
/// user interfaces into a single window and keybind for the user
/// </summary>
[RegisterComponent]
public class CharacterInterface : Component
{
public override string Name => "Character Interface Component";
[Dependency]
#pragma warning disable 649
private readonly IGameHud _gameHud;
#pragma warning restore 649
/// <summary>
/// Window to hold each of the character interfaces
/// </summary>
/// <remarks>
/// Null if it would otherwise be empty.
/// </remarks>
public SS14Window Window { get; private set; }
/// <summary>
/// Create the window with all character UIs and bind it to a keypress
/// </summary>
public override void Initialize()
{
base.Initialize();
//Use all the character ui interfaced components to create the character window
var uiComponents = Owner.GetAllComponents<ICharacterUI>().ToList();
if (uiComponents.Count == 0)
{
return;
}
Window = new CharacterWindow(uiComponents);
Window.OnClose += () => _gameHud.CharacterButtonDown = false;
}
/// <summary>
/// Dispose of window and the keypress binding
/// </summary>
public override void OnRemove()
{
base.OnRemove();
Window?.Dispose();
Window = null;
var inputMgr = IoCManager.Resolve<IInputManager>();
inputMgr.SetInputCommand(ContentKeyFunctions.OpenCharacterMenu, null);
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
IComponent component = null)
{
base.HandleMessage(message, netChannel, component);
switch (message)
{
case PlayerAttachedMsg _:
if (Window != null)
{
_gameHud.CharacterButtonVisible = true;
_gameHud.CharacterButtonToggled = b =>
{
if (b)
{
Window.Open();
}
else
{
Window.Close();
}
};
}
break;
case PlayerDetachedMsg _:
if (Window != null)
{
_gameHud.CharacterButtonVisible = false;
Window.Close();
}
break;
}
}
/// <summary>
/// A window that collects and shows all the individual character user interfaces
/// </summary>
public class CharacterWindow : SS14Window
{
private readonly VBoxContainer _contentsVBox;
public CharacterWindow(List<ICharacterUI> windowComponents)
{
Title = "Character";
_contentsVBox = new VBoxContainer();
Contents.AddChild(_contentsVBox);
windowComponents.Sort((a, b) => ((int) a.Priority).CompareTo((int) b.Priority));
foreach (var element in windowComponents)
{
_contentsVBox.AddChild(element.Scene);
}
Size = CombinedMinimumSize;
}
}
}
/// <summary>
/// Determines ordering of the character user interface, small values come sooner
/// </summary>
public enum UIPriority
{
First = 0,
Info = 5,
Species = 100,
Last = 99999
}
}

View File

@@ -1,50 +0,0 @@
using System;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Inventory;
using Content.Shared.GameObjects.Components.Items;
using Robust.Client.Graphics;
using Robust.Shared.GameObjects;
using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects.Components.Clothing
{
[RegisterComponent]
[ComponentReference(typeof(ItemComponent))]
public class ClothingComponent : ItemComponent
{
public override string Name => "Clothing";
public override uint? NetID => ContentNetIDs.CLOTHING;
public override Type StateType => typeof(ClothingComponentState);
[ViewVariables(VVAccess.ReadWrite)]
public string ClothingEquippedPrefix { get; set; }
public (RSI rsi, RSI.StateId stateId)? GetEquippedStateInfo(EquipmentSlotDefines.SlotFlags slot)
{
if (RsiPath == null)
{
return null;
}
var rsi = GetRSI();
var prefix = ClothingEquippedPrefix ?? EquippedPrefix;
var stateId = prefix != null ? $"{prefix}-equipped-{slot}" : $"equipped-{slot}";
if (rsi.TryGetState(stateId, out _))
{
return (rsi, stateId);
}
return null;
}
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
if (curState == null)
return;
var clothingComponentState = (ClothingComponentState)curState;
ClothingEquippedPrefix = clothingComponentState.ClothingEquippedPrefix;
EquippedPrefix = clothingComponentState.EquippedPrefix;
}
}
}

View File

@@ -1,31 +0,0 @@
using Content.Shared.Construction;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects.Components.Construction
{
[RegisterComponent]
public class ConstructionGhostComponent : Component
{
public override string Name => "ConstructionGhost";
[ViewVariables] public ConstructionPrototype Prototype { get; set; }
[ViewVariables] public ConstructorComponent Master { get; set; }
[ViewVariables] public int GhostID { get; set; }
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
IComponent component = null)
{
base.HandleMessage(message, netChannel, component);
switch (message)
{
case ClientEntityClickMsg clickMsg:
Master.TryStartConstruction(GhostID);
break;
}
}
}
}

View File

@@ -1,111 +0,0 @@
using System.Collections.Generic;
using Content.Client.Construction;
using Content.Client.UserInterface;
using Content.Shared.Construction;
using Content.Shared.GameObjects.Components.Construction;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
namespace Content.Client.GameObjects.Components.Construction
{
[RegisterComponent]
public class ConstructorComponent : SharedConstructorComponent
{
#pragma warning disable 649
[Dependency] private readonly IGameHud _gameHud;
#pragma warning restore 649
private int nextId;
private readonly Dictionary<int, ConstructionGhostComponent> Ghosts = new Dictionary<int, ConstructionGhostComponent>();
public ConstructionMenu ConstructionMenu { get; private set; }
public override void Initialize()
{
base.Initialize();
Owner.GetComponent<ITransformComponent>();
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
base.HandleMessage(message, netChannel, component);
switch (message)
{
case PlayerAttachedMsg _:
if (ConstructionMenu == null)
{
ConstructionMenu = new ConstructionMenu {Owner = this};
ConstructionMenu.OnClose += () => _gameHud.CraftingButtonDown = false;
}
_gameHud.CraftingButtonVisible = true;
_gameHud.CraftingButtonToggled = b =>
{
if (b)
{
ConstructionMenu.Open();
}
else
{
ConstructionMenu.Close();
}
};
break;
case PlayerDetachedMsg _:
_gameHud.CraftingButtonVisible = false;
break;
case AckStructureConstructionMessage ackMsg:
ClearGhost(ackMsg.Ack);
break;
}
}
public override void OnRemove()
{
ConstructionMenu?.Dispose();
}
public void SpawnGhost(ConstructionPrototype prototype, GridCoordinates loc, Direction dir)
{
var entMgr = IoCManager.Resolve<IClientEntityManager>();
var ghost = entMgr.SpawnEntityAt("constructionghost", loc);
var comp = ghost.GetComponent<ConstructionGhostComponent>();
comp.Prototype = prototype;
comp.Master = this;
comp.GhostID = nextId++;
ghost.GetComponent<ITransformComponent>().LocalRotation = dir.ToAngle();
var sprite = ghost.GetComponent<SpriteComponent>();
sprite.LayerSetSprite(0, prototype.Icon);
sprite.LayerSetVisible(0, true);
Ghosts.Add(comp.GhostID, comp);
}
public void TryStartConstruction(int ghostId)
{
var ghost = Ghosts[ghostId];
var transform = ghost.Owner.GetComponent<ITransformComponent>();
var msg = new TryStartStructureConstructionMessage(transform.GridPosition, ghost.Prototype.ID, transform.LocalRotation, ghostId);
SendNetworkMessage(msg);
}
public void ClearGhost(int ghostId)
{
if (Ghosts.TryGetValue(ghostId, out var ghost))
{
ghost.Owner.Delete();
Ghosts.Remove(ghostId);
}
}
}
}

View File

@@ -1,30 +0,0 @@
using System.Collections.Generic;
using Content.Shared.GameObjects;
using Robust.Shared.GameObjects;
namespace Content.Client.GameObjects
{
/// <summary>
/// Fuck I really hate doing this
/// TODO: make sure the client only gets damageable component on the clientside entity for its player mob
/// </summary>
[RegisterComponent]
public class DamageableComponent : SharedDamageableComponent
{
/// <inheritdoc />
public override string Name => "Damageable";
public Dictionary<DamageType, int> CurrentDamage = new Dictionary<DamageType, int>();
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
base.HandleComponentState(curState, nextState);
if(curState is DamageComponentState)
{
var damagestate = (DamageComponentState)curState;
CurrentDamage = damagestate.CurrentDamage;
}
}
}
}

View File

@@ -1,116 +0,0 @@
using System;
using Content.Shared.GameObjects.Components.Doors;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.GameObjects.Components.Animations;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Client.GameObjects.Components.Doors
{
public class AirlockVisualizer2D : AppearanceVisualizer
{
private const string AnimationKey = "airlock_animation";
private Animation CloseAnimation;
private Animation OpenAnimation;
public override void LoadData(YamlMappingNode node)
{
base.LoadData(node);
var openSound = node.GetNode("open_sound").AsString();
var closeSound = node.GetNode("close_sound").AsString();
CloseAnimation = new Animation {Length = TimeSpan.FromSeconds(1.2f)};
{
var flick = new AnimationTrackSpriteFlick();
CloseAnimation.AnimationTracks.Add(flick);
flick.LayerKey = DoorVisualLayers.Base;
flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("closing", 0f));
var flickUnlit = new AnimationTrackSpriteFlick();
CloseAnimation.AnimationTracks.Add(flickUnlit);
flickUnlit.LayerKey = DoorVisualLayers.BaseUnlit;
flickUnlit.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("closing_unlit", 0f));
var sound = new AnimationTrackPlaySound();
CloseAnimation.AnimationTracks.Add(sound);
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(closeSound, 0));
}
OpenAnimation = new Animation {Length = TimeSpan.FromSeconds(1.2f)};
{
var flick = new AnimationTrackSpriteFlick();
OpenAnimation.AnimationTracks.Add(flick);
flick.LayerKey = DoorVisualLayers.Base;
flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("opening", 0f));
var flickUnlit = new AnimationTrackSpriteFlick();
OpenAnimation.AnimationTracks.Add(flickUnlit);
flickUnlit.LayerKey = DoorVisualLayers.BaseUnlit;
flickUnlit.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("opening_unlit", 0f));
var sound = new AnimationTrackPlaySound();
OpenAnimation.AnimationTracks.Add(sound);
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(openSound, 0));
}
}
public override void InitializeEntity(IEntity entity)
{
if (!entity.HasComponent<AnimationPlayerComponent>())
{
entity.AddComponent<AnimationPlayerComponent>();
}
}
public override void OnChangeData(AppearanceComponent component)
{
var sprite = component.Owner.GetComponent<ISpriteComponent>();
var animPlayer = component.Owner.GetComponent<AnimationPlayerComponent>();
if (!component.TryGetData(DoorVisuals.VisualState, out DoorVisualState state))
{
state = DoorVisualState.Closed;
}
switch (state)
{
case DoorVisualState.Closed:
sprite.LayerSetState(DoorVisualLayers.Base, "closed");
sprite.LayerSetState(DoorVisualLayers.BaseUnlit, "closed_unlit");
sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, true);
break;
case DoorVisualState.Closing:
sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, true);
if (!animPlayer.HasRunningAnimation(AnimationKey))
{
animPlayer.Play(CloseAnimation, AnimationKey);
}
break;
case DoorVisualState.Opening:
sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, true);
if (!animPlayer.HasRunningAnimation(AnimationKey))
{
animPlayer.Play(OpenAnimation, AnimationKey);
}
break;
case DoorVisualState.Open:
sprite.LayerSetState(DoorVisualLayers.Base, "open");
sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, false);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
public enum DoorVisualLayers
{
Base,
BaseUnlit
}
}

View File

@@ -1,159 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Content.Client.GameObjects.Components.Clothing;
using Content.Shared.GameObjects;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
using static Content.Shared.GameObjects.SharedInventoryComponent.ClientInventoryMessage;
namespace Content.Client.GameObjects
{
/// <summary>
/// A character UI which shows items the user has equipped within his inventory
/// </summary>
[RegisterComponent]
public class ClientInventoryComponent : SharedInventoryComponent
{
private readonly Dictionary<Slots, IEntity> _slots = new Dictionary<Slots, IEntity>();
[ViewVariables]
public InventoryInterfaceController InterfaceController { get; private set; }
private ISpriteComponent _sprite;
public override void OnRemove()
{
base.OnRemove();
InterfaceController?.Dispose();
}
public override void Initialize()
{
base.Initialize();
var controllerType = ReflectionManager.LooseGetType(InventoryInstance.InterfaceControllerTypeName);
var args = new object[] {this};
InterfaceController = DynamicTypeFactory.CreateInstance<InventoryInterfaceController>(controllerType, args);
InterfaceController.Initialize();
if (Owner.TryGetComponent(out _sprite))
{
foreach (var mask in InventoryInstance.SlotMasks.OrderBy(s => InventoryInstance.SlotDrawingOrder(s)))
{
if (mask == Slots.NONE)
{
continue;
}
_sprite.LayerMapReserveBlank(mask);
}
}
// Component state already came in but we couldn't set anything visually because, well, we didn't initialize yet.
foreach (var (slot, entity) in _slots)
{
_setSlot(slot, entity);
}
}
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
base.HandleComponentState(curState, nextState);
if (curState == null)
return;
var cast = (InventoryComponentState) curState;
var doneSlots = new HashSet<Slots>();
foreach (var (slot, entityUid) in cast.Entities)
{
if (_slots.ContainsKey(slot))
{
_slots.Remove(slot);
_clearSlot(slot);
}
var entity = Owner.EntityManager.GetEntity(entityUid);
_slots[slot] = entity;
_setSlot(slot, entity);
doneSlots.Add(slot);
}
foreach (var slot in _slots.Keys.ToList())
{
if (!doneSlots.Contains(slot))
{
_clearSlot(slot);
_slots.Remove(slot);
}
}
}
private void _setSlot(Slots slot, IEntity entity)
{
if (_sprite != null && entity.TryGetComponent(out ClothingComponent clothing))
{
var flag = SlotMasks[slot];
var data = clothing.GetEquippedStateInfo(flag);
if (data == null)
{
_sprite.LayerSetVisible(slot, false);
}
else
{
var (rsi, state) = data.Value;
_sprite.LayerSetVisible(slot, true);
_sprite.LayerSetRSI(slot, rsi);
_sprite.LayerSetState(slot, state);
}
}
InterfaceController?.AddToSlot(slot, entity);
}
private void _clearSlot(Slots slot)
{
InterfaceController?.RemoveFromSlot(slot);
_sprite?.LayerSetVisible(slot, false);
}
public void SendUnequipMessage(Slots slot)
{
var unequipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Unequip);
SendNetworkMessage(unequipmessage);
}
public void SendEquipMessage(Slots slot)
{
var equipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Equip);
SendNetworkMessage(equipmessage);
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
IComponent component = null)
{
base.HandleMessage(message, netChannel, component);
switch (message)
{
case PlayerAttachedMsg _:
InterfaceController.PlayerAttached();
break;
case PlayerDetachedMsg _:
InterfaceController.PlayerDetached();
break;
}
}
}
}

View File

@@ -1,194 +0,0 @@
using System.Collections.Generic;
using Content.Client.Utility;
using JetBrains.Annotations;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
namespace Content.Client.GameObjects
{
// Dynamically instantiated by ClientInventoryComponent.
[UsedImplicitly]
public class HumanInventoryInterfaceController : InventoryInterfaceController
{
#pragma warning disable 649
[Dependency] private readonly ILocalizationManager _loc;
[Dependency] private readonly IResourceCache _resourceCache;
#pragma warning restore 649
private readonly Dictionary<Slots, List<InventoryButton>> _inventoryButtons
= new Dictionary<Slots, List<InventoryButton>>();
private InventoryButton _hudButtonPocket1;
private InventoryButton _hudButtonPocket2;
private InventoryButton _hudButtonBelt;
private InventoryButton _hudButtonBack;
private Control _quickButtonsContainer;
public HumanInventoryInterfaceController(ClientInventoryComponent owner) : base(owner)
{
}
public override void Initialize()
{
base.Initialize();
_window = new HumanInventoryWindow(_loc, _resourceCache);
foreach (var (slot, button) in _window.Buttons)
{
button.OnPressed = AddToInventory;
_inventoryButtons.Add(slot, new List<InventoryButton> {button});
}
void AddButton(out InventoryButton variable, Slots slot, string textureName)
{
var texture = _resourceCache.GetTexture($"/Textures/UserInterface/Inventory/{textureName}.png");
variable = new InventoryButton(slot, texture)
{
OnPressed = AddToInventory
};
_inventoryButtons[slot].Add(variable);
}
AddButton(out _hudButtonPocket1, Slots.POCKET1, "pocket");
AddButton(out _hudButtonPocket2, Slots.POCKET2, "pocket");
AddButton(out _hudButtonBack, Slots.BACKPACK, "back");
AddButton(out _hudButtonBelt, Slots.BELT, "belt");
_quickButtonsContainer = new HBoxContainer
{
Children =
{
_hudButtonBelt,
_hudButtonBack,
_hudButtonPocket1,
_hudButtonPocket2,
}
};
}
public override SS14Window Window => _window;
private HumanInventoryWindow _window;
public override void AddToSlot(Slots slot, IEntity entity)
{
base.AddToSlot(slot, entity);
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
{
return;
}
entity.TryGetComponent(out ISpriteComponent sprite);
foreach (var button in buttons)
{
button.SpriteView.Sprite = sprite;
button.OnPressed = RemoveFromInventory;
}
}
public override void RemoveFromSlot(Slots slot)
{
base.RemoveFromSlot(slot);
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
{
return;
}
foreach (var button in buttons)
{
button.SpriteView.Sprite = null;
button.OnPressed = AddToInventory;
}
}
public override void PlayerAttached()
{
base.PlayerAttached();
GameHud.InventoryQuickButtonContainer.AddChild(_quickButtonsContainer);
}
public override void PlayerDetached()
{
base.PlayerDetached();
GameHud.InventoryQuickButtonContainer.RemoveChild(_quickButtonsContainer);
}
private class HumanInventoryWindow : SS14Window
{
private const int ButtonSize = 64;
private const int ButtonSeparation = 2;
private const int RightSeparation = 2;
public IReadOnlyDictionary<Slots, InventoryButton> Buttons { get; }
public HumanInventoryWindow(ILocalizationManager loc, IResourceCache resourceCache)
{
Title = loc.GetString("Your Inventory");
Resizable = false;
var buttonDict = new Dictionary<Slots, InventoryButton>();
Buttons = buttonDict;
const int width = ButtonSize * 4 + ButtonSeparation * 3 + RightSeparation;
const int height = ButtonSize * 4 + ButtonSeparation * 3;
var windowContents = new Control {CustomMinimumSize = (width, height)};
Contents.AddChild(windowContents);
void AddButton(Slots slot, string textureName, Vector2 position)
{
var texture = resourceCache.GetTexture($"/Textures/UserInterface/Inventory/{textureName}.png");
var button = new InventoryButton(slot, texture)
{
Position = position
};
windowContents.AddChild(button);
buttonDict.Add(slot, button);
}
const int size = ButtonSize;
const int sep = ButtonSeparation;
const int rSep = RightSeparation;
// Left column.
AddButton(Slots.EYES, "glasses", (0, size + sep));
AddButton(Slots.INNERCLOTHING, "uniform", (0, 2 * (size + sep)));
AddButton(Slots.EXOSUITSLOT1, "suit_storage", (0, 3 * (size + sep)));
// Middle column.
AddButton(Slots.HEAD, "head", (size + sep, 0));
AddButton(Slots.MASK, "mask", (size + sep, size + sep));
AddButton(Slots.OUTERCLOTHING, "suit", (size + sep, 2 * (size + sep)));
AddButton(Slots.SHOES, "shoes", (size + sep, 3 * (size + sep)));
// Right column
AddButton(Slots.EARS, "ears", (2 * (size + sep), 0));
AddButton(Slots.IDCARD, "mask", (2 * (size + sep), size + sep));
AddButton(Slots.GLOVES, "gloves", (2 * (size + sep), 2 * (size + sep)));
// Far right column.
AddButton(Slots.BACKPACK, "back", (rSep + 3 * (size + sep), 0));
AddButton(Slots.BELT, "belt", (rSep + 3 * (size + sep), size + sep));
AddButton(Slots.POCKET1, "pocket", (rSep + 3 * (size + sep), 2 * (size + sep)));
AddButton(Slots.POCKET2, "pocket", (rSep + 3 * (size + sep), 3 * (size + sep)));
Size = CombinedMinimumSize;
}
}
}
}

View File

@@ -1,40 +0,0 @@
using System;
using Content.Shared.GameObjects.Components.Inventory;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
namespace Content.Client.GameObjects
{
public sealed class InventoryButton : MarginContainer
{
public EquipmentSlotDefines.Slots Slot { get; }
public EntityUid EntityUid { get; set; }
public BaseButton Button { get; }
public SpriteView SpriteView { get; }
public Action<BaseButton.ButtonEventArgs> OnPressed { get; set; }
public InventoryButton(EquipmentSlotDefines.Slots slot, Texture texture)
{
Slot = slot;
CustomMinimumSize = (64, 64);
AddChild(Button = new TextureButton
{
TextureNormal = texture,
Scale = (2, 2),
});
Button.OnPressed += e => OnPressed?.Invoke(e);
AddChild(SpriteView = new SpriteView
{
MouseFilter = MouseFilterMode.Ignore,
Scale = (2, 2)
});
}
}
}

View File

@@ -1,79 +0,0 @@
using System;
using Content.Client.UserInterface;
using Content.Shared.GameObjects.Components.Inventory;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Client.GameObjects
{
public abstract class InventoryInterfaceController : IDisposable
{
// ReSharper disable once UnassignedGetOnlyAutoProperty
[field: Dependency] protected IGameHud GameHud { get; }
protected InventoryInterfaceController(ClientInventoryComponent owner)
{
Owner = owner;
}
public virtual void Initialize()
{
}
public abstract SS14Window Window { get; }
protected ClientInventoryComponent Owner { get; }
public virtual void PlayerAttached()
{
GameHud.InventoryButtonVisible = true;
GameHud.InventoryButtonToggled = b =>
{
if (b)
{
Window.Open();
}
else
{
Window.Close();
}
};
}
public virtual void PlayerDetached()
{
GameHud.InventoryButtonVisible = false;
Window.Close();
}
public virtual void Dispose()
{
}
public virtual void AddToSlot(EquipmentSlotDefines.Slots slot, IEntity entity)
{
}
public virtual void RemoveFromSlot(EquipmentSlotDefines.Slots slot)
{
}
protected void RemoveFromInventory(BaseButton.ButtonEventArgs args)
{
args.Button.Pressed = false;
var control = (InventoryButton) args.Button.Parent;
Owner.SendUnequipMessage(control.Slot);
}
protected void AddToInventory(BaseButton.ButtonEventArgs args)
{
args.Button.Pressed = false;
var control = (InventoryButton) args.Button.Parent;
Owner.SendEquipMessage(control.Slot);
}
}
}

View File

@@ -1,287 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Content.Client.GameObjects.EntitySystems;
using JetBrains.Annotations;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using static Robust.Client.GameObjects.SpriteComponent;
namespace Content.Client.GameObjects.Components.IconSmoothing
{
// TODO: Potential improvements:
// Defer updating of these.
// Get told by somebody to use a loop.
/// <summary>
/// Makes sprites of other grid-aligned entities like us connect.
/// </summary>
/// <remarks>
/// The system is based on Baystation12's smoothwalling, and thus will work with those.
/// To use, set <c>base</c> equal to the prefix of the corner states in the sprite base RSI.
/// Any objects with the same <c>key</c> will connect.
/// </remarks>
[RegisterComponent]
public class IconSmoothComponent : Component
{
private string _smoothKey;
private string _stateBase;
private IconSmoothingMode _mode;
public override string Name => "IconSmooth";
internal ISpriteComponent Sprite { get; private set; }
internal SnapGridComponent SnapGrid { get; private set; }
private (GridId, MapIndices) _lastPosition;
/// <summary>
/// We will smooth with other objects with the same key.
/// </summary>
public string SmoothKey => _smoothKey;
/// <summary>
/// Prepended to the RSI state.
/// </summary>
public string StateBase => _stateBase;
/// <summary>
/// Mode that controls how the icon should be selected.
/// </summary>
public IconSmoothingMode Mode => _mode;
/// <summary>
/// Used by <see cref="IconSmoothSystem"/> to reduce redundant updates.
/// </summary>
internal int UpdateGeneration { get; set; }
public override void Initialize()
{
base.Initialize();
SnapGrid = Owner.GetComponent<SnapGridComponent>();
Sprite = Owner.GetComponent<ISpriteComponent>();
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataFieldCached(ref _stateBase, "base", "");
serializer.DataFieldCached(ref _smoothKey, "key", null);
serializer.DataFieldCached(ref _mode, "mode", IconSmoothingMode.Corners);
}
public override void Startup()
{
base.Startup();
SnapGrid.OnPositionChanged += SnapGridOnPositionChanged;
Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(null, SnapGrid.Offset, Mode));
if (Mode == IconSmoothingMode.Corners)
{
var state0 = $"{StateBase}0";
Sprite.LayerMapSet(CornerLayers.SE, Sprite.AddLayerState(state0));
Sprite.LayerSetDirOffset(CornerLayers.SE, DirectionOffset.None);
Sprite.LayerMapSet(CornerLayers.NE, Sprite.AddLayerState(state0));
Sprite.LayerSetDirOffset(CornerLayers.NE, DirectionOffset.CounterClockwise);
Sprite.LayerMapSet(CornerLayers.NW, Sprite.AddLayerState(state0));
Sprite.LayerSetDirOffset(CornerLayers.NW, DirectionOffset.Flip);
Sprite.LayerMapSet(CornerLayers.SW, Sprite.AddLayerState(state0));
Sprite.LayerSetDirOffset(CornerLayers.SW, DirectionOffset.Clockwise);
}
}
internal virtual void CalculateNewSprite()
{
switch (Mode)
{
case IconSmoothingMode.Corners:
CalculateNewSpriteCorers();
break;
case IconSmoothingMode.CardinalFlags:
CalculateNewSpriteCardinal();
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private void CalculateNewSpriteCardinal()
{
var dirs = CardinalConnectDirs.None;
if (MatchingEntity(SnapGrid.GetInDir(Direction.North)))
dirs |= CardinalConnectDirs.North;
if (MatchingEntity(SnapGrid.GetInDir(Direction.South)))
dirs |= CardinalConnectDirs.South;
if (MatchingEntity(SnapGrid.GetInDir(Direction.East)))
dirs |= CardinalConnectDirs.East;
if (MatchingEntity(SnapGrid.GetInDir(Direction.West)))
dirs |= CardinalConnectDirs.West;
Sprite.LayerSetState(0, $"{StateBase}{(int) dirs}");
}
private void CalculateNewSpriteCorers()
{
var n = MatchingEntity(SnapGrid.GetInDir(Direction.North));
var ne = MatchingEntity(SnapGrid.GetInDir(Direction.NorthEast));
var e = MatchingEntity(SnapGrid.GetInDir(Direction.East));
var se = MatchingEntity(SnapGrid.GetInDir(Direction.SouthEast));
var s = MatchingEntity(SnapGrid.GetInDir(Direction.South));
var sw = MatchingEntity(SnapGrid.GetInDir(Direction.SouthWest));
var w = MatchingEntity(SnapGrid.GetInDir(Direction.West));
var nw = MatchingEntity(SnapGrid.GetInDir(Direction.NorthWest));
// ReSharper disable InconsistentNaming
var cornerNE = CornerFill.None;
var cornerSE = CornerFill.None;
var cornerSW = CornerFill.None;
var cornerNW = CornerFill.None;
// ReSharper restore InconsistentNaming
if (n)
{
cornerNE |= CornerFill.CounterClockwise;
cornerNW |= CornerFill.Clockwise;
}
if (ne)
{
cornerNE |= CornerFill.Diagonal;
}
if (e)
{
cornerNE |= CornerFill.Clockwise;
cornerSE |= CornerFill.CounterClockwise;
}
if (se)
{
cornerSE |= CornerFill.Diagonal;
}
if (s)
{
cornerSE |= CornerFill.Clockwise;
cornerSW |= CornerFill.CounterClockwise;
}
if (sw)
{
cornerSW |= CornerFill.Diagonal;
}
if (w)
{
cornerSW |= CornerFill.Clockwise;
cornerNW |= CornerFill.CounterClockwise;
}
if (nw)
{
cornerNW |= CornerFill.Diagonal;
}
Sprite.LayerSetState(CornerLayers.NE, $"{StateBase}{(int) cornerNE}");
Sprite.LayerSetState(CornerLayers.SE, $"{StateBase}{(int) cornerSE}");
Sprite.LayerSetState(CornerLayers.SW, $"{StateBase}{(int) cornerSW}");
Sprite.LayerSetState(CornerLayers.NW, $"{StateBase}{(int) cornerNW}");
}
public override void Shutdown()
{
SnapGrid.OnPositionChanged -= SnapGridOnPositionChanged;
Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode));
base.Shutdown();
}
private void SnapGridOnPositionChanged()
{
Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode));
_lastPosition = (Owner.Transform.GridID, SnapGrid.Position);
}
[System.Diagnostics.Contracts.Pure]
protected bool MatchingEntity(IEnumerable<IEntity> candidates)
{
foreach (var entity in candidates)
{
if (!entity.TryGetComponent(out IconSmoothComponent other))
{
continue;
}
if (other.SmoothKey == SmoothKey)
{
return true;
}
}
return false;
}
[Flags]
private enum CardinalConnectDirs : byte
{
None = 0,
North = 1,
South = 2,
East = 4,
West = 8
}
[Flags]
public enum CornerFill : byte
{
// These values are pulled from Baystation12.
// I'm too lazy to convert the state names.
None = 0,
// The cardinal tile counter-clockwise of this corner is filled.
CounterClockwise = 1,
// The diagonal tile in the direction of this corner.
Diagonal = 2,
// The cardinal tile clockwise of this corner is filled.
Clockwise = 4,
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum CornerLayers
{
SE,
NE,
NW,
SW,
}
}
/// <summary>
/// Controls the mode with which icon smoothing is calculated.
/// </summary>
[PublicAPI]
public enum IconSmoothingMode
{
/// <summary>
/// Each icon is made up of 4 corners, each of which can get a different state depending on
/// adjacent entities clockwise, counter-clockwise and diagonal with the corner.
/// </summary>
Corners,
/// <summary>
/// There are 16 icons, only one of which is used at once.
/// The icon selected is a bit field made up of the cardinal direction flags that have adjacent entities.
/// </summary>
CardinalFlags,
}
}

View File

@@ -0,0 +1,226 @@
using Content.Shared.GameObjects;
using Content.Shared.Input;
using SS14.Client.GameObjects;
using SS14.Client.Interfaces.Input;
using SS14.Client.UserInterface;
using SS14.Client.UserInterface.Controls;
using SS14.Client.UserInterface.CustomControls;
using SS14.Shared.ContentPack;
using SS14.Shared.GameObjects;
using SS14.Shared.GameObjects.Serialization;
using SS14.Shared.Input;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.Network;
using SS14.Shared.IoC;
using SS14.Shared.Log;
using SS14.Shared.Maths;
using SS14.Shared.Utility;
using System;
using System.Collections.Generic;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
using static Content.Shared.GameObjects.SharedInventoryComponent.ClientInventoryMessage;
using static Content.Shared.GameObjects.SharedInventoryComponent.ServerInventoryMessage;
namespace Content.Client.GameObjects
{
public class ClientInventoryComponent : SharedInventoryComponent
{
private InventoryWindow Window;
private string TemplateName = "HumanInventory"; //stored for serialization purposes
private InputCommand OpenMenuCommand;
public override void OnRemove()
{
base.OnRemove();
Window.Dispose();
}
public override void ExposeData(EntitySerializer serializer)
{
base.ExposeData(serializer);
Window = new InventoryWindow(this);
OpenMenuCommand = InputCommand.FromDelegate(() => { Window.AddToScreen(); Window.Open(); });
serializer.DataField(ref TemplateName, "Template", "HumanInventory");
Window.CreateInventory(TemplateName);
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
var inputMgr = IoCManager.Resolve<IInputManager>();
switch (message)
{
//Updates what we are storing in UI slots
case ServerInventoryMessage msg:
if (msg.Updatetype == ServerInventoryUpdate.Addition)
{
Window.AddToSlot(msg);
}
else if (msg.Updatetype == ServerInventoryUpdate.Removal)
{
Window.RemoveFromSlot(msg);
}
break;
case PlayerAttachedMsg _:
inputMgr.SetInputCommand(ContentKeyFunctions.OpenCharacterMenu, OpenMenuCommand);
break;
case PlayerDetachedMsg _:
inputMgr.SetInputCommand(ContentKeyFunctions.OpenCharacterMenu, null);
break;
}
}
public void SendUnequipMessage(Slots slot)
{
var unequipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Unequip);
SendNetworkMessage(unequipmessage);
}
public void SendEquipMessage(Slots slot)
{
var equipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Equip);
SendNetworkMessage(equipmessage);
}
/// <summary>
/// Temporary window to hold the basis for inventory hud
/// </summary>
private class InventoryWindow : SS14Window
{
private int elements_x;
private GridContainer GridContainer;
private List<Slots> IndexedSlots;
private Dictionary<Slots, InventoryButton> InventorySlots = new Dictionary<Slots, InventoryButton>(); //ordered dictionary?
private ClientInventoryComponent InventoryComponent;
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Inventory/HumanInventory.tscn");
public InventoryWindow(ClientInventoryComponent inventory)
{
InventoryComponent = inventory;
HideOnClose = true;
}
/// <summary>
/// Creates a grid container filled with slot buttons loaded from an inventory template
/// </summary>
/// <param name="TemplateName"></param>
public void CreateInventory(string TemplateName)
{
Type type = AppDomain.CurrentDomain.GetAssemblyByName("Content.Shared").GetType("Content.Shared.GameObjects." + TemplateName);
Inventory inventory = (Inventory)Activator.CreateInstance(type);
elements_x = inventory.Columns;
GridContainer = (GridContainer)Contents.GetChild("PanelContainer").GetChild("CenterContainer").GetChild("GridContainer");
GridContainer.Columns = elements_x;
IndexedSlots = new List<Slots>(inventory.SlotMasks);
foreach (Slots slot in IndexedSlots)
{
InventoryButton newbutton = new InventoryButton(slot);
if (slot == Slots.NONE)
{
//TODO: Re-enable when godot grid container maintains grid with invisible elements
//newbutton.Visible = false;
}
else
{
//Store slot button and give it the default onpress behavior for empty elements
newbutton.GetChild<Button>("Button").OnPressed += AddToInventory;
InventorySlots.Add(slot, newbutton);
}
if (SlotNames.ContainsKey(slot))
{
newbutton.GetChild<Button>("Button").Text = SlotNames[slot];
}
GridContainer.AddChild(newbutton);
}
}
/// <summary>
/// Adds the item we have equipped to the slot texture and prepares the slot button for removal
/// </summary>
/// <param name="message"></param>
public void AddToSlot(ServerInventoryMessage message)
{
InventoryButton button = InventorySlots[message.Inventoryslot];
var entity = IoCManager.Resolve<IEntityManager>().GetEntity(message.EntityUid);
button.EntityUid = message.EntityUid;
var container = button.GetChild("CenterContainer");
button.GetChild<Button>("Button").OnPressed += RemoveFromInventory;
button.GetChild<Button>("Button").OnPressed -= AddToInventory;
//Gets entity sprite and assigns it to button texture
if (entity.TryGetComponent(out IconComponent sprite))
{
var tex = sprite.Icon.Default;
var rect = button.GetChild("CenterContainer").GetChild<TextureRect>("TextureRect");
if (tex != null)
{
rect.Texture = tex;
rect.Scale = new Vector2(Math.Min(CalculateMinimumSize().X, 32) / tex.Height, Math.Min(CalculateMinimumSize().Y, 32) / tex.Height);
}
else
{
throw new NotImplementedException();
}
}
}
/// <summary>
/// Remove element from the UI and update its button to blank texture and prepare for insertion again
/// </summary>
/// <param name="message"></param>
public void RemoveFromSlot(ServerInventoryMessage message)
{
InventoryButton button = InventorySlots[message.Inventoryslot];
button.GetChild("CenterContainer").GetChild<TextureRect>("TextureRect").Texture = null;
button.EntityUid = EntityUid.Invalid;
button.GetChild<Button>("Button").OnPressed -= RemoveFromInventory;
button.GetChild<Button>("Button").OnPressed += AddToInventory;
}
private void RemoveFromInventory(BaseButton.ButtonEventArgs args)
{
args.Button.Pressed = false;
var control = (InventoryButton)args.Button.Parent;
InventoryComponent.SendUnequipMessage(control.Slot);
}
private void AddToInventory(BaseButton.ButtonEventArgs args)
{
args.Button.Pressed = false;
var control = (InventoryButton)args.Button.Parent;
InventoryComponent.SendEquipMessage(control.Slot);
}
}
private class InventoryButton : Control
{
public Slots Slot;
public EntityUid EntityUid;
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Inventory/StorageSlot.tscn");
public InventoryButton(Slots slot)
{
Slot = slot;
}
}
}
}

View File

@@ -1,62 +1,22 @@
using System.Collections.Generic;
using System.Linq;
using Content.Client.Interfaces.GameObjects;
using Content.Client.Interfaces.GameObjects;
using Content.Client.UserInterface;
using Content.Shared.GameObjects;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using SS14.Client.Interfaces.UserInterface;
using SS14.Shared.GameObjects;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.IoC;
using System.Collections.Generic;
namespace Content.Client.GameObjects
{
[RegisterComponent]
[ComponentReference(typeof(IHandsComponent))]
public class HandsComponent : SharedHandsComponent, IHandsComponent
{
private HandsGui _gui;
#pragma warning disable 649
[Dependency] private readonly IGameHud _gameHud;
#pragma warning restore 649
[ViewVariables] private readonly Dictionary<string, IEntity> _hands = new Dictionary<string, IEntity>();
[ViewVariables] public string ActiveIndex { get; private set; }
[ViewVariables] private ISpriteComponent _sprite;
[ViewVariables] public IEntity ActiveHand => GetEntity(ActiveIndex);
public override void OnRemove()
{
base.OnRemove();
_gui?.Dispose();
}
public override void Initialize()
{
base.Initialize();
if (Owner.TryGetComponent(out _sprite))
{
foreach (var slot in _hands.Keys)
{
_sprite.LayerMapReserveBlank($"hand-{slot}");
_setHand(slot, _hands[slot]);
}
}
}
private readonly Dictionary<string, IEntity> hands = new Dictionary<string, IEntity>();
public string ActiveIndex { get; private set; }
public IEntity GetEntity(string index)
{
if (_hands.TryGetValue(index, out var entity))
if (hands.TryGetValue(index, out var entity))
{
return entity;
}
@@ -64,109 +24,33 @@ namespace Content.Client.GameObjects
return null;
}
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
public override void HandleComponentState(ComponentState state)
{
if (curState == null)
return;
var cast = (HandsComponentState) curState;
foreach (var (slot, uid) in cast.Hands)
var cast = (HandsComponentState)state;
hands.Clear();
foreach (var hand in cast.Hands)
{
IEntity entity = null;
try
{
entity = Owner.EntityManager.GetEntity(uid);
entity = Owner.EntityManager.GetEntity(hand.Value);
}
catch
{
// Nothing.
}
_hands[slot] = entity;
_setHand(slot, entity);
}
foreach (var slot in _hands.Keys.ToList())
{
if (!cast.Hands.ContainsKey(slot))
{
_hands[slot] = null;
_setHand(slot, null);
}
hands[hand.Key] = entity;
}
ActiveIndex = cast.ActiveIndex;
_gui?.UpdateHandIcons();
}
private void _setHand(string hand, IEntity entity)
{
if (_sprite == null)
// Tell UI to update.
var uiMgr = IoCManager.Resolve<IUserInterfaceManager>();
if (!uiMgr.StateRoot.TryGetChild<HandsGui>("HandsGui", out var control))
{
return;
}
if (entity == null)
{
_sprite.LayerSetVisible($"hand-{hand}", false);
return;
}
var item = entity.GetComponent<ItemComponent>();
var maybeInhands = item.GetInHandStateInfo(hand);
if (!maybeInhands.HasValue)
{
_sprite.LayerSetVisible($"hand-{hand}", false);
}
else
{
var (rsi, state) = maybeInhands.Value;
_sprite.LayerSetVisible($"hand-{hand}", true);
_sprite.LayerSetState($"hand-{hand}", state, rsi);
}
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
if (!serializer.Reading)
{
return;
}
foreach (var slot in serializer.ReadDataFieldCached("hands", new List<string>()))
{
_hands.Add(slot, null);
}
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null,
IComponent component = null)
{
base.HandleMessage(message, netChannel, component);
switch (message)
{
case PlayerAttachedMsg _:
if (_gui == null)
{
_gui = new HandsGui();
}
else
{
_gui.Parent?.RemoveChild(_gui);
}
_gameHud.HandsContainer.AddChild(_gui);
_gui.UpdateHandIcons();
break;
case PlayerDetachedMsg _:
_gui.Parent?.RemoveChild(_gui);
break;
control = new HandsGui();
uiMgr.StateRoot.AddChild(control);
}
control.UpdateHandIcons();
}
public void SendChangeHand(string index)
@@ -174,14 +58,9 @@ namespace Content.Client.GameObjects
SendNetworkMessage(new ClientChangedHandMsg(index));
}
public void AttackByInHand(string index)
{
SendNetworkMessage(new ClientAttackByInHandMsg(index));
}
public void UseActiveHand()
{
if (GetEntity(ActiveIndex) != null)
if(GetEntity(ActiveIndex) != null)
{
SendNetworkMessage(new ActivateInhandMsg());
}

View File

@@ -1,74 +0,0 @@
using System;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Items;
using Robust.Client.Graphics;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.ResourceManagement;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Renderable;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects
{
[RegisterComponent]
public class ItemComponent : Component
{
public override string Name => "Item";
public override uint? NetID => ContentNetIDs.ITEM;
public override Type StateType => typeof(ItemComponentState);
[ViewVariables] protected ResourcePath RsiPath;
private string _equippedPrefix;
[ViewVariables(VVAccess.ReadWrite)]
public string EquippedPrefix
{
get => _equippedPrefix;
set => _equippedPrefix = value;
}
public (RSI rsi, RSI.StateId stateId)? GetInHandStateInfo(string hand)
{
if (RsiPath == null)
{
return null;
}
var rsi = GetRSI();
var stateId = EquippedPrefix != null ? $"{EquippedPrefix}-inhand-{hand}" : $"inhand-{hand}";
if (rsi.TryGetState(stateId, out _))
{
return (rsi, stateId);
}
return null;
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataFieldCached(ref RsiPath, "sprite", null);
serializer.DataFieldCached(ref _equippedPrefix, "prefix", null);
}
protected RSI GetRSI()
{
var resourceCache = IoCManager.Resolve<IResourceCache>();
return resourceCache.GetResource<RSIResource>(SharedSpriteComponent.TextureRoot / RsiPath).RSI;
}
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
if(curState == null)
return;
var itemComponentState = (ItemComponentState)curState;
EquippedPrefix = itemComponentState.EquippedPrefix;
}
}
}

View File

@@ -1,209 +0,0 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Content.Client.GameObjects.Components.IconSmoothing;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Maths;
using static Robust.Client.GameObjects.SpriteComponent;
namespace Content.Client.GameObjects.Components
{
// TODO: Over layers should be placed ABOVE the window itself too.
// This is gonna require a client entity & parenting,
// so IsMapTransform being naive is gonna be a problem.
/// <summary>
/// Override of icon smoothing to handle the specific complexities of low walls.
/// </summary>
[RegisterComponent]
[ComponentReference(typeof(IconSmoothComponent))]
public class LowWallComponent : IconSmoothComponent
{
public override string Name => "LowWall";
public CornerFill LastCornerNE { get; private set; }
public CornerFill LastCornerSE { get; private set; }
public CornerFill LastCornerSW { get; private set; }
public CornerFill LastCornerNW { get; private set; }
public override void Startup()
{
base.Startup();
var overState0 = $"{StateBase}over_0";
Sprite.LayerMapSet(OverCornerLayers.SE, Sprite.AddLayerState(overState0));
Sprite.LayerSetDirOffset(OverCornerLayers.SE, DirectionOffset.None);
Sprite.LayerMapSet(OverCornerLayers.NE, Sprite.AddLayerState(overState0));
Sprite.LayerSetDirOffset(OverCornerLayers.NE, DirectionOffset.CounterClockwise);
Sprite.LayerMapSet(OverCornerLayers.NW, Sprite.AddLayerState(overState0));
Sprite.LayerSetDirOffset(OverCornerLayers.NW, DirectionOffset.Flip);
Sprite.LayerMapSet(OverCornerLayers.SW, Sprite.AddLayerState(overState0));
Sprite.LayerSetDirOffset(OverCornerLayers.SW, DirectionOffset.Clockwise);
}
internal override void CalculateNewSprite()
{
base.CalculateNewSprite();
var (n, nl) = MatchingWall(SnapGrid.GetInDir(Direction.North));
var (ne, nel) = MatchingWall(SnapGrid.GetInDir(Direction.NorthEast));
var (e, el) = MatchingWall(SnapGrid.GetInDir(Direction.East));
var (se, sel) = MatchingWall(SnapGrid.GetInDir(Direction.SouthEast));
var (s, sl) = MatchingWall(SnapGrid.GetInDir(Direction.South));
var (sw, swl) = MatchingWall(SnapGrid.GetInDir(Direction.SouthWest));
var (w, wl) = MatchingWall(SnapGrid.GetInDir(Direction.West));
var (nw, nwl) = MatchingWall(SnapGrid.GetInDir(Direction.NorthWest));
// ReSharper disable InconsistentNaming
var cornerNE = CornerFill.None;
var cornerSE = CornerFill.None;
var cornerSW = CornerFill.None;
var cornerNW = CornerFill.None;
var lowCornerNE = CornerFill.None;
var lowCornerSE = CornerFill.None;
var lowCornerSW = CornerFill.None;
var lowCornerNW = CornerFill.None;
// ReSharper restore InconsistentNaming
if (n)
{
cornerNE |= CornerFill.CounterClockwise;
cornerNW |= CornerFill.Clockwise;
if (!nl)
{
lowCornerNE |= CornerFill.CounterClockwise;
lowCornerNW |= CornerFill.Clockwise;
}
}
if (ne)
{
cornerNE |= CornerFill.Diagonal;
if (!nel && (nl || el || n && e))
{
lowCornerNE |= CornerFill.Diagonal;
}
}
if (e)
{
cornerNE |= CornerFill.Clockwise;
cornerSE |= CornerFill.CounterClockwise;
if (!el)
{
lowCornerNE |= CornerFill.Clockwise;
lowCornerSE |= CornerFill.CounterClockwise;
}
}
if (se)
{
cornerSE |= CornerFill.Diagonal;
if (!sel && (sl || el || s && e))
{
lowCornerSE |= CornerFill.Diagonal;
}
}
if (s)
{
cornerSE |= CornerFill.Clockwise;
cornerSW |= CornerFill.CounterClockwise;
if (!sl)
{
lowCornerSE |= CornerFill.Clockwise;
lowCornerSW |= CornerFill.CounterClockwise;
}
}
if (sw)
{
cornerSW |= CornerFill.Diagonal;
if (!swl && (sl || wl || s && w))
{
lowCornerSW |= CornerFill.Diagonal;
}
}
if (w)
{
cornerSW |= CornerFill.Clockwise;
cornerNW |= CornerFill.CounterClockwise;
if (!wl)
{
lowCornerSW |= CornerFill.Clockwise;
lowCornerNW |= CornerFill.CounterClockwise;
}
}
if (nw)
{
cornerNW |= CornerFill.Diagonal;
if (!nwl && (nl || wl || n && w))
{
lowCornerNW |= CornerFill.Diagonal;
}
}
Sprite.LayerSetState(CornerLayers.NE, $"{StateBase}{(int) cornerNE}");
Sprite.LayerSetState(CornerLayers.SE, $"{StateBase}{(int) cornerSE}");
Sprite.LayerSetState(CornerLayers.SW, $"{StateBase}{(int) cornerSW}");
Sprite.LayerSetState(CornerLayers.NW, $"{StateBase}{(int) cornerNW}");
Sprite.LayerSetState(OverCornerLayers.NE, $"{StateBase}over_{(int) lowCornerNE}");
Sprite.LayerSetState(OverCornerLayers.SE, $"{StateBase}over_{(int) lowCornerSE}");
Sprite.LayerSetState(OverCornerLayers.SW, $"{StateBase}over_{(int) lowCornerSW}");
Sprite.LayerSetState(OverCornerLayers.NW, $"{StateBase}over_{(int) lowCornerNW}");
LastCornerNE = cornerNE;
LastCornerSE = cornerSE;
LastCornerSW = cornerSW;
LastCornerNW = cornerNW;
foreach (var entity in SnapGrid.GetLocal())
{
if (entity.TryGetComponent(out WindowComponent window))
{
window.UpdateSprite();
}
}
}
[System.Diagnostics.Contracts.Pure]
private (bool connected, bool lowWall) MatchingWall(IEnumerable<IEntity> candidates)
{
foreach (var entity in candidates)
{
if (!entity.TryGetComponent(out IconSmoothComponent other))
{
continue;
}
if (other.SmoothKey == SmoothKey)
{
return (true, other is LowWallComponent);
}
}
return (false, false);
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
private enum OverCornerLayers
{
SE,
NE,
NW,
SW,
}
}
}

View File

@@ -1,89 +0,0 @@
using System;
using Content.Shared.GameObjects.Components.Mobs;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Maths;
namespace Content.Client.GameObjects.Components.Mobs
{
[RegisterComponent]
[ComponentReference(typeof(SharedCameraRecoilComponent))]
public sealed class CameraRecoilComponent : SharedCameraRecoilComponent
{
// Maximum rate of magnitude restore towards 0 kick.
private const float RestoreRateMax = 1.5f;
// Minimum rate of magnitude restore towards 0 kick.
private const float RestoreRateMin = 0.5f;
// Time in seconds since the last kick that lerps RestoreRateMin and RestoreRateMax
private const float RestoreRateRamp = 0.05f;
// The maximum magnitude of the kick applied to the camera at any point.
private const float KickMagnitudeMax = 0.25f;
private Vector2 _currentKick;
private float _lastKickTime;
private EyeComponent _eye;
public override void Initialize()
{
base.Initialize();
_eye = Owner.GetComponent<EyeComponent>();
}
public override void Kick(Vector2 recoil)
{
// Use really bad math to "dampen" kicks when we're already kicked.
var existing = _currentKick.Length;
var dampen = existing/KickMagnitudeMax;
_currentKick += recoil * (1-dampen);
if (_currentKick.Length > KickMagnitudeMax)
{
_currentKick = _currentKick.Normalized * KickMagnitudeMax;
}
_lastKickTime = 0;
_updateEye();
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
base.HandleMessage(message, netChannel, component);
switch (message)
{
case RecoilKickMessage msg:
Kick(msg.Recoil);
break;
}
}
public void FrameUpdate(float frameTime)
{
var magnitude = _currentKick.Length;
if (magnitude <= 0.005f)
{
_currentKick = Vector2.Zero;
_updateEye();
return;
}
// Continually restore camera to 0.
var normalized = _currentKick.Normalized;
var restoreRate = FloatMath.Lerp(RestoreRateMin, RestoreRateMax, Math.Min(1, _lastKickTime/RestoreRateRamp));
var restore = normalized * restoreRate * frameTime;
_currentKick -= restore;
_updateEye();
}
private void _updateEye()
{
_eye.Offset = _currentKick;
}
}
}

View File

@@ -1,21 +0,0 @@
using Content.Client.GameObjects.Components.Actor;
using Robust.Client.UserInterface;
namespace Content.Client.GameObjects.Components.Mobs
{
/// <summary>
/// An interface which is gathered to assemble the character window from multiple components
/// </summary>
public interface ICharacterUI
{
/// <summary>
/// The godot control which holds the character user interface to be included in the window
/// </summary>
Control Scene { get; }
/// <summary>
/// The order it will appear in the character UI, higher is lower
/// </summary>
UIPriority Priority { get; }
}
}

View File

@@ -1,171 +0,0 @@
using System.Collections.Generic;
using Content.Client.GameObjects.Components.Actor;
using Content.Client.Graphics.Overlays;
using Content.Client.UserInterface;
using Content.Client.Utility;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Mobs;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Renderable;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
namespace Content.Client.GameObjects
{
/// <summary>
/// A character UI component which shows the current damage state of the mob (living/dead)
/// </summary>
[RegisterComponent]
public class SpeciesUI : SharedSpeciesComponent//, ICharacterUI
{
private StatusEffectsUI _ui;
/// <summary>
/// Holds the godot control for the species window
/// </summary>
private SpeciesWindow _window;
/// <summary>
/// An enum representing the current state being applied to the user
/// </summary>
private ScreenEffects _currentEffect = ScreenEffects.None;
#pragma warning disable 649
// Required dependencies
[Dependency] private readonly IOverlayManager _overlayManager;
[Dependency] private readonly IPlayerManager _playerManager;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
[Dependency] private readonly IResourceCache _resourceCache;
#pragma warning restore 649
//Relevant interface implementation for the character UI controller
public Control Scene => _window;
public UIPriority Priority => UIPriority.Species;
/// <summary>
/// Allows calculating if we need to act due to this component being controlled by the current mob
/// </summary>
private bool CurrentlyControlled => _playerManager.LocalPlayer.ControlledEntity == Owner;
/// <summary>
/// Holds the screen effects that can be applied mapped ot their relevant overlay
/// </summary>
private Dictionary<ScreenEffects, Overlay> EffectsDictionary;
public override void OnRemove()
{
base.OnRemove();
_window.Dispose();
}
public override void OnAdd()
{
base.OnAdd();
_window = new SpeciesWindow();
_ui = new StatusEffectsUI();
EffectsDictionary = new Dictionary<ScreenEffects, Overlay>()
{
{ ScreenEffects.CircleMask, new CircleMaskOverlay() },
{ ScreenEffects.GradientCircleMask, new GradientCircleMask() }
};
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
switch (message)
{
case HudStateChange msg:
if (CurrentlyControlled)
{
ChangeHudIcon(msg);
}
break;
case PlayerAttachedMsg _:
_ui.Parent?.RemoveChild(_ui);
_userInterfaceManager.StateRoot.AddChild(_ui);
ApplyOverlay();
break;
case PlayerDetachedMsg _:
_ui.Parent?.RemoveChild(_ui);
RemoveOverlay();
break;
}
}
private void ChangeHudIcon(HudStateChange changeMessage)
{
var path = SharedSpriteComponent.TextureRoot / changeMessage.StateSprite;
var texture = _resourceCache.GetTexture(path);
_window.SetIcon(texture);
_ui.SetHealthIcon(texture);
SetOverlay(changeMessage);
}
private void SetOverlay(HudStateChange message)
{
RemoveOverlay();
_currentEffect = message.effect;
ApplyOverlay();
}
private void RemoveOverlay()
{
if (_currentEffect != ScreenEffects.None)
{
var appliedEffect = EffectsDictionary[_currentEffect];
_overlayManager.RemoveOverlay(appliedEffect.ID);
}
_currentEffect = ScreenEffects.None;
}
private void ApplyOverlay()
{
if (_currentEffect != ScreenEffects.None)
{
var overlay = EffectsDictionary[_currentEffect];
if (_overlayManager.HasOverlay(overlay.ID))
{
return;
}
_overlayManager.AddOverlay(overlay);
}
}
private class SpeciesWindow : TextureRect
{
public SpeciesWindow()
{
SizeFlagsHorizontal = SizeFlags.ShrinkCenter;
SizeFlagsVertical = SizeFlags.None;
Texture = IoCManager.Resolve<IResourceCache>().GetTexture("/Textures/Mob/UI/Human/human0.png");
}
public void SetIcon(Texture texture)
{
Texture = texture;
}
}
}
}

View File

@@ -1,35 +0,0 @@
using Content.Shared.GameObjects.Components.Mobs;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Maths;
namespace Content.Client.GameObjects.Components.Mobs
{
public class SpeciesVisualizer2D : AppearanceVisualizer
{
public override void InitializeEntity(IEntity entity)
{
base.InitializeEntity(entity);
}
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
var sprite = component.Owner.GetComponent<ISpriteComponent>();
if (component.TryGetData<SharedSpeciesComponent.MobState>(SharedSpeciesComponent.MobVisuals.RotationState, out var state))
{
switch (state)
{
case SharedSpeciesComponent.MobState.Stand:
sprite.Rotation = 0;
break;
case SharedSpeciesComponent.MobState.Down:
sprite.Rotation = Angle.FromDegrees(90);
break;
}
}
}
}
}

View File

@@ -1,35 +0,0 @@
using System;
using Content.Shared.GameObjects.Components.Movement;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
namespace Content.Client.GameObjects.Components.Movement
{
[UsedImplicitly]
public class HandTeleporterVisualizer2D : AppearanceVisualizer
{
public override void OnChangeData(AppearanceComponent component)
{
var sprite = component.Owner.GetComponent<ISpriteComponent>();
if (!component.TryGetData(TeleporterVisuals.VisualState, out TeleporterVisualState state))
{
state = TeleporterVisualState.Ready;
}
switch (state)
{
case TeleporterVisualState.Charging:
sprite.LayerSetState(0, "charging");
break;
case TeleporterVisualState.Ready:
sprite.LayerSetState(0, "ready");
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}

View File

@@ -1,55 +0,0 @@
using Content.Shared.GameObjects.Components.Movement;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
namespace Content.Client.GameObjects.Components.Movement
{
[UsedImplicitly]
public class PortalVisualizer2D : AppearanceVisualizer
{
public override void InitializeEntity(IEntity entity)
{
base.InitializeEntity(entity);
var sprite = entity.GetComponent<ISpriteComponent>();
sprite.LayerMapSet(Layers.Portal, sprite.AddLayerState("portal-pending"));
sprite.LayerSetShader(Layers.Portal, "unshaded");
}
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
var sprite = component.Owner.GetComponent<ISpriteComponent>();
if (component.TryGetData<PortalState>(PortalVisuals.State, out var state))
{
switch (state)
{
case PortalState.Pending:
sprite.LayerSetState(Layers.Portal, "portal-pending");
break;
// TODO: Spritework here?
case PortalState.UnableToTeleport:
sprite.LayerSetState(Layers.Portal, "portal-unconnected");
break;
case PortalState.RecentlyTeleported:
sprite.LayerSetState(Layers.Portal, "portal-unconnected");
break;
}
}
else
{
sprite.LayerSetState(Layers.Portal, "portal-pending");
}
}
enum Layers
{
Portal
}
}
}

View File

@@ -1,177 +0,0 @@
using System;
using Content.Client.UserInterface;
using Content.Shared.GameObjects.Components.Power;
using NJsonSchema.Validation;
using OpenTK.Graphics.OpenGL4;
using Robust.Client.GameObjects.Components.UserInterface;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
namespace Content.Client.GameObjects.Components.Power
{
public class ApcBoundUserInterface : BoundUserInterface
{
private ApcWindow _window;
private BaseButton _breakerButton;
private Label _externalPowerStateLabel;
private ProgressBar _chargeBar;
protected override void Open()
{
base.Open();
_window = new ApcWindow
{
MarginRight = 426.0f, MarginBottom = 270.0f
};
_window.OnClose += Close;
_window.OpenCenteredMinSize();
_breakerButton = _window.BreakerButton;
_breakerButton.OnPressed += _ => SendMessage(new ApcToggleMainBreakerMessage());
_externalPowerStateLabel = _window.ExternalPowerStateLabel;
_chargeBar = _window.ChargeBar;
}
public ApcBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
var castState = (ApcBoundInterfaceState) state;
_breakerButton.Pressed = castState.MainBreaker;
switch (castState.ApcExternalPower)
{
case ApcExternalPowerState.None:
_externalPowerStateLabel.Text = "None";
_externalPowerStateLabel.SetOnlyStyleClass(NanoStyle.StyleClassPowerStateNone);
break;
case ApcExternalPowerState.Low:
_externalPowerStateLabel.Text = "Low";
_externalPowerStateLabel.SetOnlyStyleClass(NanoStyle.StyleClassPowerStateLow);
break;
case ApcExternalPowerState.Good:
_externalPowerStateLabel.Text = "Good";
_externalPowerStateLabel.SetOnlyStyleClass(NanoStyle.StyleClassPowerStateGood);
break;
default:
throw new ArgumentOutOfRangeException();
}
_chargeBar.Value = castState.Charge;
UpdateChargeBarColor(castState.Charge);
float ChargePercentage = (castState.Charge / _chargeBar.MaxValue) * 100.0f;
_window.ChargePercentage.Text = " " + ChargePercentage.ToString("0.00") + "%";
}
private void UpdateChargeBarColor(float charge)
{
float normalizedCharge = charge / _chargeBar.MaxValue;
float leftHue = 0.0f;// Red
float middleHue = 0.066f;// Orange
float rightHue = 0.33f;// Green
float saturation = 1.0f;// Uniform saturation
float value = 0.8f;// Uniform value / brightness
float alpha = 1.0f;// Uniform alpha
// These should add up to 1.0 or your transition won't be smooth
float leftSideSize = 0.5f;// Fraction of _chargeBar lerped from leftHue to middleHue
float rightSideSize = 0.5f;// Fraction of _chargeBar lerped from middleHue to rightHue
float finalHue;
if (normalizedCharge <= leftSideSize)
{
normalizedCharge /= leftSideSize;// Adjust range to 0.0 to 1.0
finalHue = FloatMath.Lerp(leftHue, middleHue, normalizedCharge);
}
else
{
normalizedCharge = (normalizedCharge - leftSideSize) / rightSideSize;// Adjust range to 0.0 to 1.0.
finalHue = FloatMath.Lerp(middleHue, rightHue, normalizedCharge);
}
// Check if null first to avoid repeatedly creating this.
if (_chargeBar.ForegroundStyleBoxOverride == null)
{
_chargeBar.ForegroundStyleBoxOverride = new StyleBoxFlat();
}
var foregroundStyleBoxOverride = (StyleBoxFlat)_chargeBar.ForegroundStyleBoxOverride;
foregroundStyleBoxOverride.BackgroundColor =
Color.FromHsv(new Vector4(finalHue, saturation, value, alpha));
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window.Dispose();
}
}
private class ApcWindow : SS14Window
{
public Button BreakerButton { get; set; }
public Label ExternalPowerStateLabel { get; set; }
public ProgressBar ChargeBar { get; set; }
public Label ChargePercentage { get; set; }
public ApcWindow()
{
Title = "APC";
var rows = new VBoxContainer("Rows");
var statusHeader = new Label("StatusHeader") { Text = "Power Status: " };
rows.AddChild(statusHeader);
var breaker = new HBoxContainer("Breaker");
var breakerLabel = new Label("Label") { Text = "Main Breaker: " };
BreakerButton = new CheckButton {Name = "Breaker", Text = "Toggle"};
breaker.AddChild(breakerLabel);
breaker.AddChild(BreakerButton);
rows.AddChild(breaker);
var externalStatus = new HBoxContainer("ExternalStatus");
var externalStatusLabel = new Label("Label") { Text = "External Power: " };
ExternalPowerStateLabel = new Label("Status") { Text = "Good" };
ExternalPowerStateLabel.SetOnlyStyleClass(NanoStyle.StyleClassPowerStateGood);
externalStatus.AddChild(externalStatusLabel);
externalStatus.AddChild(ExternalPowerStateLabel);
rows.AddChild(externalStatus);
var charge = new HBoxContainer("Charge");
var chargeLabel = new Label("Label") { Text = "Charge:" };
ChargeBar = new ProgressBar("Charge")
{
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
MinValue = 0.0f,
MaxValue = 1.0f,
Page = 0.0f,
Value = 0.5f
};
ChargePercentage = new Label("ChargePercentage");
charge.AddChild(chargeLabel);
charge.AddChild(ChargeBar);
charge.AddChild(ChargePercentage);
rows.AddChild(charge);
Contents.AddChild(rows);
}
}
}
}

View File

@@ -1,67 +0,0 @@
using Content.Shared.GameObjects.Components.Power;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
namespace Content.Client.GameObjects.Components.Power
{
public class ApcVisualizer2D : AppearanceVisualizer
{
public override void InitializeEntity(IEntity entity)
{
base.InitializeEntity(entity);
var sprite = entity.GetComponent<ISpriteComponent>();
sprite.LayerMapSet(Layers.ChargeState, sprite.AddLayerState("apco3-0"));
sprite.LayerSetShader(Layers.ChargeState, "unshaded");
sprite.LayerMapSet(Layers.Lock, sprite.AddLayerState("apcox-0"));
sprite.LayerSetShader(Layers.Lock, "unshaded");
sprite.LayerMapSet(Layers.Equipment, sprite.AddLayerState("apco0-3"));
sprite.LayerSetShader(Layers.Equipment, "unshaded");
sprite.LayerMapSet(Layers.Lighting, sprite.AddLayerState("apco1-3"));
sprite.LayerSetShader(Layers.Lighting, "unshaded");
sprite.LayerMapSet(Layers.Environment, sprite.AddLayerState("apco2-3"));
sprite.LayerSetShader(Layers.Environment, "unshaded");
}
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
var sprite = component.Owner.GetComponent<ISpriteComponent>();
if (component.TryGetData<ApcChargeState>(ApcVisuals.ChargeState, out var state))
{
switch (state)
{
case ApcChargeState.Lack:
sprite.LayerSetState(Layers.ChargeState, "apco3-0");
break;
case ApcChargeState.Charging:
sprite.LayerSetState(Layers.ChargeState, "apco3-1");
break;
case ApcChargeState.Full:
sprite.LayerSetState(Layers.ChargeState, "apco3-2");
break;
}
}
else
{
sprite.LayerSetState(Layers.ChargeState, "apco3-0");
}
}
enum Layers
{
ChargeState,
Lock,
Equipment,
Lighting,
Environment,
}
}
}

View File

@@ -1,48 +0,0 @@
using Content.Shared.GameObjects.Components.Power;
using Content.Shared.Utility;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Client.GameObjects.Components.Power
{
public class PowerCellVisualizer2D : AppearanceVisualizer
{
private string _prefix;
public override void LoadData(YamlMappingNode node)
{
base.LoadData(node);
_prefix = node.GetNode("prefix").AsString();
}
public override void InitializeEntity(IEntity entity)
{
base.InitializeEntity(entity);
var sprite = entity.GetComponent<ISpriteComponent>();
sprite.LayerMapSet(Layers.Charge, sprite.AddLayerState($"{_prefix}_100"));
sprite.LayerSetShader(Layers.Charge, "unshaded");
}
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
var sprite = component.Owner.GetComponent<ISpriteComponent>();
if (component.TryGetData(PowerCellVisuals.ChargeLevel, out float fraction))
{
sprite.LayerSetState(Layers.Charge, $"{_prefix}_{ContentHelpers.RoundToLevels(fraction, 1, 5) * 25}");
}
}
private enum Layers
{
Charge
}
}
}

View File

@@ -1,16 +1,15 @@
using Content.Shared.GameObjects.Components.Power;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Power;
using SS14.Client.UserInterface.Controls;
using SS14.Client.UserInterface.CustomControls;
using SS14.Shared.GameObjects;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.Network;
namespace Content.Client.GameObjects.Components.Power
{
[RegisterComponent]
public class PowerDebugTool : SharedPowerDebugTool
{
SS14Window LastWindow;
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
base.HandleMessage(message, netChannel, component);
@@ -18,16 +17,13 @@ namespace Content.Client.GameObjects.Components.Power
switch (message)
{
case OpenDataWindowMsg msg:
if (LastWindow != null && !LastWindow.Disposed)
var window = new SS14Window
{
LastWindow.Dispose();
}
LastWindow = new SS14Window()
{
Title = "Power Debug Tool",
Title = "Power Debug Tool"
};
LastWindow.Contents.AddChild(new Label() { Text = msg.Data });
LastWindow.Open();
window.Contents.AddChild(new Label() { Text = msg.Data });
window.AddToScreen();
window.Open();
break;
}
}

View File

@@ -1,77 +0,0 @@
using Content.Shared.GameObjects.Components.Power;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Content.Client.GameObjects.Components.Power
{
public class SmesVisualizer2D : AppearanceVisualizer
{
public override void InitializeEntity(IEntity entity)
{
base.InitializeEntity(entity);
var sprite = entity.GetComponent<ISpriteComponent>();
sprite.LayerMapSet(Layers.Input, sprite.AddLayerState("smes-oc0"));
sprite.LayerSetShader(Layers.Input, "unshaded");
sprite.LayerMapSet(Layers.Charge, sprite.AddLayerState("smes-og1"));
sprite.LayerSetShader(Layers.Charge, "unshaded");
sprite.LayerSetVisible(Layers.Charge, false);
sprite.LayerMapSet(Layers.Output, sprite.AddLayerState("smes-op0"));
sprite.LayerSetShader(Layers.Output, "unshaded");
}
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
var sprite = component.Owner.GetComponent<ISpriteComponent>();
if (!component.TryGetData<int>(SmesVisuals.LastChargeLevel, out var level) || level == 0)
{
sprite.LayerSetVisible(Layers.Charge, false);
}
else
{
sprite.LayerSetVisible(Layers.Charge, true);
sprite.LayerSetState(Layers.Charge, $"smes-og{level}");
}
if (component.TryGetData<ChargeState>(SmesVisuals.LastChargeState, out var state))
{
switch (state)
{
case ChargeState.Still:
sprite.LayerSetState(Layers.Input, "smes-oc0");
sprite.LayerSetState(Layers.Output, "smes-op1");
break;
case ChargeState.Charging:
sprite.LayerSetState(Layers.Input, "smes-oc1");
sprite.LayerSetState(Layers.Output, "smes-op1");
break;
case ChargeState.Discharging:
sprite.LayerSetState(Layers.Input, "smes-oc0");
sprite.LayerSetState(Layers.Output, "smes-op2");
break;
}
}
else
{
sprite.LayerSetState(Layers.Input, "smes-oc0");
sprite.LayerSetState(Layers.Output, "smes-op1");
}
}
enum Layers
{
Input,
Charge,
Output,
}
}
}

View File

@@ -1,102 +0,0 @@
using System.Collections.Generic;
using Content.Client.Research;
using Content.Shared.GameObjects.Components.Research;
using Content.Shared.Research;
using Robust.Client.GameObjects.Components.UserInterface;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects.Components.Research
{
public class LatheBoundUserInterface : BoundUserInterface
{
#pragma warning disable CS0649
[Dependency]
private IPrototypeManager _prototypeManager;
#pragma warning restore
[ViewVariables]
private LatheMenu menu;
[ViewVariables]
private LatheQueueMenu queueMenu;
public MaterialStorageComponent Storage { get; private set; }
public SharedLatheComponent Lathe { get; private set; }
public LatheDatabaseComponent Database { get; private set; }
[ViewVariables]
public Queue<LatheRecipePrototype> QueuedRecipes => _queuedRecipes;
private Queue<LatheRecipePrototype> _queuedRecipes = new Queue<LatheRecipePrototype>();
public LatheBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
SendMessage(new SharedLatheComponent.LatheSyncRequestMessage());
}
protected override void Open()
{
base.Open();
IoCManager.InjectDependencies(this);
if (!Owner.Owner.TryGetComponent(out MaterialStorageComponent storage)
|| !Owner.Owner.TryGetComponent(out SharedLatheComponent lathe)
|| !Owner.Owner.TryGetComponent(out LatheDatabaseComponent database)) return;
Storage = storage;
Lathe = lathe;
Database = database;
menu = new LatheMenu {Owner = this};
queueMenu = new LatheQueueMenu { Owner = this };
menu.OnClose += Close;
menu.Populate();
menu.PopulateMaterials();
menu.QueueButton.OnPressed += (args) => { queueMenu.OpenCentered(); };
storage.OnMaterialStorageChanged += menu.PopulateDisabled;
storage.OnMaterialStorageChanged += menu.PopulateMaterials;
menu.OpenCentered();
}
public void Queue(LatheRecipePrototype recipe, int quantity = 1)
{
SendMessage(new SharedLatheComponent.LatheQueueRecipeMessage(recipe.ID, quantity));
}
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
{
switch (message)
{
case SharedLatheComponent.LatheProducingRecipeMessage msg:
if (!_prototypeManager.TryIndex(msg.ID, out LatheRecipePrototype recipe)) break;
queueMenu.SetInfo(recipe);
break;
case SharedLatheComponent.LatheStoppedProducingRecipeMessage msg:
queueMenu.ClearInfo();
break;
case SharedLatheComponent.LatheFullQueueMessage msg:
_queuedRecipes.Clear();
foreach (var id in msg.Recipes)
{
if (!_prototypeManager.TryIndex(id, out LatheRecipePrototype recipePrototype)) break;
_queuedRecipes.Enqueue(recipePrototype);
}
queueMenu.PopulateList();
break;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
menu?.Dispose();
queueMenu?.Dispose();
}
}
}

View File

@@ -1,30 +0,0 @@
using Content.Shared.GameObjects.Components.Research;
using Content.Shared.Research;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
namespace Content.Client.GameObjects.Components.Research
{
[RegisterComponent]
[ComponentReference(typeof(SharedLatheDatabaseComponent))]
public class LatheDatabaseComponent : SharedLatheDatabaseComponent
{
#pragma warning disable CS0649
[Dependency]
private IPrototypeManager _prototypeManager;
#pragma warning restore
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
base.HandleComponentState(curState, nextState);
if (!(curState is LatheDatabaseState state)) return;
Clear();
foreach (var ID in state.Recipes)
{
if(!_prototypeManager.TryIndex(ID, out LatheRecipePrototype recipe)) continue;
AddRecipe(recipe);
}
}
}
}

View File

@@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Research;
using Robust.Shared.GameObjects;
namespace Content.Client.GameObjects.Components.Research
{
[RegisterComponent]
[ComponentReference(typeof(SharedMaterialStorageComponent))]
public class MaterialStorageComponent : SharedMaterialStorageComponent
{
protected override Dictionary<string, int> Storage { get; set; } = new Dictionary<string, int>();
public event Action OnMaterialStorageChanged;
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
base.HandleComponentState(curState, nextState);
if (!(curState is MaterialStorageState state)) return;
Storage = state.Storage;
OnMaterialStorageChanged?.Invoke();
}
}
}

View File

@@ -1,108 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Sound;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
using Robust.Shared.Timers;
namespace Content.Client.GameObjects.Components.Sound
{
[RegisterComponent]
public class SoundComponent : SharedSoundComponent
{
private readonly List<ScheduledSound> _schedules = new List<ScheduledSound>();
private AudioSystem _audioSystem;
private Random Random;
public override void StopAllSounds()
{
foreach (var schedule in _schedules)
{
schedule.Play = false;
}
_schedules.Clear();
}
public override void StopScheduledSound(string filename)
{
foreach (var schedule in _schedules.ToArray())
{
if (schedule.Filename != filename) continue;
schedule.Play = false;
_schedules.Remove(schedule);
}
}
public override void AddScheduledSound(ScheduledSound schedule)
{
_schedules.Add(schedule);
Play(schedule);
}
public void Play(ScheduledSound schedule)
{
if (!schedule.Play) return;
if (Random == null) Random = new Random(Owner.Uid.GetHashCode() ^ DateTime.Now.GetHashCode());
Timer.Spawn((int) schedule.Delay + (Random.Next((int) schedule.RandomDelay)),() =>
{
if (!schedule.Play) return; // We make sure this hasn't changed.
if (_audioSystem == null) _audioSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
_audioSystem.Play(schedule.Filename, Owner, schedule.AudioParams);
if (schedule.Times == 0)
{
_schedules.Remove(schedule);
return;
}
if (schedule.Times > 0)
schedule.Times--;
Play(schedule);
});
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
base.HandleMessage(message, netChannel, component);
switch (message)
{
case ScheduledSoundMessage msg:
AddScheduledSound(msg.Schedule);
break;
case StopSoundScheduleMessage msg:
StopScheduledSound(msg.Filename);
break;
case StopAllSoundsMessage msg:
StopAllSounds();
break;
}
}
public override void Initialize()
{
base.Initialize();
IoCManager.Resolve<IEntitySystemManager>().TryGetEntitySystem(out _audioSystem);
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
if (serializer.Writing) return;
serializer.TryReadDataField("schedules", out List<ScheduledSound> schedules);
if (schedules == null) return;
foreach (var schedule in schedules)
{
if (schedule == null) continue;
AddScheduledSound(schedule);
}
}
}
}

View File

@@ -1,23 +1,24 @@
using System;
using System.Collections.Generic;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Storage;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using SS14.Client.GameObjects;
using SS14.Client.UserInterface;
using SS14.Client.UserInterface.Controls;
using SS14.Client.UserInterface.CustomControls;
using SS14.Shared.GameObjects;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.Network;
using SS14.Shared.IoC;
using SS14.Shared.Log;
using SS14.Shared.Maths;
using SS14.Shared.Utility;
using System;
using System.Collections.Generic;
namespace Content.Client.GameObjects.Components.Storage
{
/// <summary>
/// Client version of item storage containers, contains a UI which displays stored entities and their size
/// </summary>
[RegisterComponent]
public class ClientStorageComponent : SharedStorageComponent
{
private Dictionary<EntityUid, int> StoredEntities { get; set; } = new Dictionary<EntityUid, int>();
@@ -30,18 +31,14 @@ namespace Content.Client.GameObjects.Components.Storage
base.OnAdd();
Window = new StorageWindow()
{ StorageEntity = this};
{ StorageEntity = this };
}
public override void OnRemove()
{
Window.Dispose();
base.OnRemove();
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
base.OnRemove();
}
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
@@ -56,9 +53,6 @@ namespace Content.Client.GameObjects.Components.Storage
case OpenStorageUIMessage msg:
OpenUI();
break;
case CloseStorageUIMessage msg:
CloseUI();
break;
}
}
@@ -79,14 +73,10 @@ namespace Content.Client.GameObjects.Components.Storage
/// </summary>
private void OpenUI()
{
Window.AddToScreen();
Window.Open();
}
private void CloseUI()
{
Window.Close();
}
/// <summary>
/// Function for clicking one of the stored entity buttons in the UI, tells server to remove that entity
/// </summary>
@@ -106,46 +96,18 @@ namespace Content.Client.GameObjects.Components.Storage
private Label Information;
public ClientStorageComponent StorageEntity;
public StorageWindow()
{
Size = new Vector2(180.0f, 320.0f);
}
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Storage/Storage.tscn");
protected override void Initialize()
{
base.Initialize();
Title = "Storage Item";
RectClipContent = true;
HideOnClose = true;
VSplitContainer = new VBoxContainer("VSplitContainer");
Information = new Label("Information")
{
Text = "Items: 0 Volume: 0/0 Stuff",
SizeFlagsVertical = SizeFlags.ShrinkCenter
};
VSplitContainer.AddChild(Information);
var listScrollContainer = new ScrollContainer("ListScrollContainer")
{
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsHorizontal = SizeFlags.FillExpand,
HScrollEnabled = true,
VScrollEnabled = true
};
EntityList = new VBoxContainer("EntityList")
{
SizeFlagsHorizontal = SizeFlags.FillExpand
};
listScrollContainer.AddChild(EntityList);
VSplitContainer.AddChild(listScrollContainer);
Contents.AddChild(VSplitContainer);
}
public override void Close()
{
StorageEntity.SendNetworkMessage(new CloseStorageUIMessage());
base.Close();
// Get all the controls.
VSplitContainer = Contents.GetChild("VSplitContainer");
EntityList = VSplitContainer.GetChild("ListScrollContainer").GetChild<VBoxContainer>("EntityList");
Information = VSplitContainer.GetChild<Label>("Information");
}
/// <summary>
@@ -165,15 +127,29 @@ namespace Content.Client.GameObjects.Components.Storage
{
EntityuID = entityuid.Key
};
var container = button.GetChild("HBoxContainer");
button.ActualButton.OnToggled += OnItemButtonToggled;
//Name and Size labels set
button.EntityName.Text = entity.Name;
button.EntitySize.Text = string.Format("{0}", entityuid.Value);
container.GetChild<Label>("Name").Text = entity.Name;
container.GetChild<Control>("Control").GetChild<Label>("Size").Text = string.Format("{0}", entityuid.Value);
//Gets entity sprite and assigns it to button texture
if (entity.TryGetComponent(out ISpriteComponent sprite))
if (entity.TryGetComponent(out IconComponent icon))
{
button.EntitySpriteView.Sprite = sprite;
var tex = icon.Icon.Default;
var rect = container.GetChild("TextureWrap").GetChild<TextureRect>("TextureRect");
if (tex != null)
{
rect.Texture = tex;
// Copypasted but replaced with 32 dunno if good
var scale = (float)32 / tex.Height;
rect.Scale = new Vector2(scale, scale);
}
else
{
rect.Dispose();
}
}
EntityList.AddChild(button);
@@ -205,64 +181,17 @@ namespace Content.Client.GameObjects.Components.Storage
/// <summary>
/// Button created for each entity that represents that item in the storage UI, with a texture, and name and size label
/// </summary>
private class EntityButton : PanelContainer
private class EntityButton : Control
{
public EntityUid EntityuID { get; set; }
public Button ActualButton { get; private set; }
public SpriteView EntitySpriteView { get; private set; }
public Control EntityControl { get; private set; }
public Label EntityName { get; private set; }
public Label EntitySize { get; private set; }
protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Storage/StorageEntity.tscn");
protected override void Initialize()
{
base.Initialize();
ActualButton = new Button("Button")
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsVertical = SizeFlags.FillExpand,
ToggleMode = true,
MouseFilter = MouseFilterMode.Stop
};
AddChild(ActualButton);
var hBoxContainer = new HBoxContainer("HBoxContainer") {MouseFilter = MouseFilterMode.Ignore};
EntitySpriteView = new SpriteView("SpriteView")
{
CustomMinimumSize = new Vector2(32.0f, 32.0f), MouseFilter = MouseFilterMode.Ignore
};
EntityName = new Label("Name")
{
SizeFlagsVertical = SizeFlags.ShrinkCenter,
Text = "Backpack",
MouseFilter = MouseFilterMode.Ignore
};
hBoxContainer.AddChild(EntitySpriteView);
hBoxContainer.AddChild(EntityName);
EntityControl = new Control("Control")
{
SizeFlagsHorizontal = SizeFlags.FillExpand, MouseFilter = MouseFilterMode.Ignore
};
EntitySize = new Label("Size")
{
SizeFlagsVertical = SizeFlags.ShrinkCenter,
Text = "Size 6",
Align = Label.AlignMode.Right,
AnchorLeft = 1.0f,
AnchorRight = 1.0f,
AnchorBottom = 0.5f,
AnchorTop = 0.5f,
MarginLeft = -38.0f,
MarginTop = -7.0f,
MarginRight = -5.0f,
MarginBottom = 7.0f
};
EntityControl.AddChild(EntitySize);
hBoxContainer.AddChild(EntityControl);
AddChild(hBoxContainer);
ActualButton = GetChild<Button>("Button");
}
}
}

View File

@@ -1,47 +0,0 @@
using Content.Shared.GameObjects.Components.Storage;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Client.GameObjects.Components.Storage
{
public sealed class StorageVisualizer2D : AppearanceVisualizer
{
private string _stateOpen;
private string _stateClosed;
public override void LoadData(YamlMappingNode node)
{
base.LoadData(node);
if (node.TryGetNode("state_open", out var child))
{
_stateOpen = child.AsString();
}
if (node.TryGetNode("state_closed", out child))
{
_stateClosed = child.AsString();
}
}
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
if (!component.Owner.TryGetComponent(out ISpriteComponent sprite))
{
return;
}
component.TryGetData(StorageVisuals.Open, out bool open);
sprite.LayerSetState(StorageVisualLayers.Door, open ? _stateOpen : _stateClosed);
}
}
public enum StorageVisualLayers
{
Door
}
}

View File

@@ -1,51 +0,0 @@
using Content.Shared.Maps;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
namespace Content.Client.GameObjects.Components
{
/// <summary>
/// Simple component that automatically hides the sibling <see cref="ISpriteComponent"/> when the tile it's on
/// is not a sub floor (plating).
/// </summary>
/// <seealso cref="ContentTileDefinition.IsSubFloor"/>
[RegisterComponent]
public sealed class SubFloorHideComponent : Component
{
private SnapGridComponent _snapGridComponent;
public override string Name => "SubFloorHide";
public override void Initialize()
{
base.Initialize();
_snapGridComponent = Owner.GetComponent<SnapGridComponent>();
}
public override void Startup()
{
base.Startup();
_snapGridComponent.OnPositionChanged += SnapGridOnPositionChanged;
Owner.EntityManager.RaiseEvent(Owner, new SubFloorHideDirtyEvent());
}
public override void Shutdown()
{
base.Shutdown();
_snapGridComponent.OnPositionChanged -= SnapGridOnPositionChanged;
}
private void SnapGridOnPositionChanged()
{
Owner.EntityManager.RaiseEvent(Owner, new SubFloorHideDirtyEvent());
}
}
internal sealed class SubFloorHideDirtyEvent : EntitySystemMessage
{
}
}

View File

@@ -1,76 +0,0 @@
using System;
using Content.Shared.GameObjects.Components.Triggers;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.GameObjects.Components.Animations;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Client.GameObjects.Components.Doors
{
public class TimerTriggerVisualizer2D : AppearanceVisualizer
{
private const string AnimationKey = "priming_animation";
private Animation PrimingAnimation;
public override void LoadData(YamlMappingNode node)
{
base.LoadData(node);
var countdownSound = node.GetNode("countdown_sound").AsString();
PrimingAnimation = new Animation { Length = TimeSpan.MaxValue };
{
var flick = new AnimationTrackSpriteFlick();
PrimingAnimation.AnimationTracks.Add(flick);
flick.LayerKey = TriggerVisualLayers.Base;
flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame("primed", 0f));
var sound = new AnimationTrackPlaySound();
PrimingAnimation.AnimationTracks.Add(sound);
sound.KeyFrames.Add(new AnimationTrackPlaySound.KeyFrame(countdownSound, 0));
}
}
public override void InitializeEntity(IEntity entity)
{
if (!entity.HasComponent<AnimationPlayerComponent>())
{
entity.AddComponent<AnimationPlayerComponent>();
}
}
public override void OnChangeData(AppearanceComponent component)
{
var sprite = component.Owner.GetComponent<ISpriteComponent>();
var animPlayer = component.Owner.GetComponent<AnimationPlayerComponent>();
if (!component.TryGetData(TriggerVisuals.VisualState, out TriggerVisualState state))
{
state = TriggerVisualState.Unprimed;
}
switch (state)
{
case TriggerVisualState.Primed:
if (!animPlayer.HasRunningAnimation(AnimationKey))
{
animPlayer.Play(PrimingAnimation, AnimationKey);
}
break;
case TriggerVisualState.Unprimed:
sprite.LayerSetState(0, "icon");
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
public enum TriggerVisualLayers
{
Base
}
}

View File

@@ -1,41 +0,0 @@
using Content.Shared.GameObjects.Components.Weapons.Ranged;
using Content.Shared.Utility;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Client.GameObjects.Components.Weapons.Ranged
{
public sealed class BallisticMagazineVisualizer2D : AppearanceVisualizer
{
private string _baseState;
private int _steps;
public override void LoadData(YamlMappingNode node)
{
base.LoadData(node);
_baseState = node.GetNode("base_state").AsString();
_steps = node.GetNode("steps").AsInt();
}
public override void OnChangeData(AppearanceComponent component)
{
var sprite = component.Owner.GetComponent<ISpriteComponent>();
if (!component.TryGetData(BallisticMagazineVisuals.AmmoCapacity, out int capacity))
{
return;
}
if (!component.TryGetData(BallisticMagazineVisuals.AmmoLeft, out int current))
{
return;
}
var step = ContentHelpers.RoundToLevels(current, capacity, _steps);
sprite.LayerSetState(0, $"{_baseState}-{step}");
}
}
}

View File

@@ -1,50 +0,0 @@
using Content.Shared.GameObjects.Components.Weapons.Ranged;
using Content.Shared.Utility;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Client.GameObjects.Components.Weapons.Ranged
{
public sealed class BallisticMagazineWeaponVisualizer2D : AppearanceVisualizer
{
private string _baseState;
private int _steps;
public override void LoadData(YamlMappingNode node)
{
base.LoadData(node);
_baseState = node.GetNode("base_state").AsString();
_steps = node.GetNode("steps").AsInt();
}
public override void OnChangeData(AppearanceComponent component)
{
var sprite = component.Owner.GetComponent<ISpriteComponent>();
component.TryGetData(BallisticMagazineWeaponVisuals.MagazineLoaded, out bool loaded);
if (loaded)
{
if (!component.TryGetData(BallisticMagazineWeaponVisuals.AmmoCapacity, out int capacity))
{
return;
}
if (!component.TryGetData(BallisticMagazineWeaponVisuals.AmmoLeft, out int current))
{
return;
}
var step = ContentHelpers.RoundToLevels(current, capacity, _steps);
sprite.LayerSetState(0, $"{_baseState}-{step}");
}
else
{
sprite.LayerSetState(0, _baseState);
}
}
}
}

View File

@@ -1,29 +0,0 @@
using System;
using Content.Shared.GameObjects.Components.Weapons.Ranged;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Content.Client.GameObjects.Components.Weapons.Ranged
{
[RegisterComponent]
public sealed class ClientRangedWeaponComponent : SharedRangedWeaponComponent
{
private TimeSpan _lastFireTime;
private int _tick;
public void TryFire(GridCoordinates worldPos)
{
var curTime = IoCManager.Resolve<IGameTiming>().CurTime;
var span = curTime - _lastFireTime;
if (span.TotalSeconds < 1 / FireRate)
{
return;
}
_lastFireTime = curTime;
SendNetworkMessage(new FireMessage(worldPos, _tick++));
}
}
}

View File

@@ -1,33 +0,0 @@
using Content.Shared.GameObjects.Components.Power;
using Content.Shared.Utility;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Client.GameObjects.Components.Power
{
public class HitscanWeaponVisualizer2D : AppearanceVisualizer
{
private string _prefix;
public override void LoadData(YamlMappingNode node)
{
base.LoadData(node);
_prefix = node.GetNode("prefix").AsString();
}
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);
var sprite = component.Owner.GetComponent<ISpriteComponent>();
if (component.TryGetData(PowerCellVisuals.ChargeLevel, out float fraction))
{
sprite.LayerSetState(0, $"{_prefix}_{ContentHelpers.RoundToLevels(fraction, 1, 5) * 25}");
}
}
}
}

View File

@@ -1,92 +0,0 @@
using Content.Client.GameObjects.EntitySystems;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.Serialization;
using static Content.Client.GameObjects.Components.IconSmoothing.IconSmoothComponent;
namespace Content.Client.GameObjects.Components
{
[RegisterComponent]
public sealed class WindowComponent : Component
{
public override string Name => "Window";
private string _stateBase;
private ISpriteComponent _sprite;
private SnapGridComponent _snapGrid;
public override void Initialize()
{
base.Initialize();
_sprite = Owner.GetComponent<ISpriteComponent>();
_snapGrid = Owner.GetComponent<SnapGridComponent>();
}
public override void Startup()
{
base.Startup();
_snapGrid.OnPositionChanged += SnapGridOnPositionChanged;
Owner.EntityManager.RaiseEvent(Owner, new WindowSmoothDirtyEvent());
var state0 = $"{_stateBase}0";
_sprite.LayerMapSet(CornerLayers.SE, _sprite.AddLayerState(state0));
_sprite.LayerSetDirOffset(CornerLayers.SE, SpriteComponent.DirectionOffset.None);
_sprite.LayerMapSet(CornerLayers.NE, _sprite.AddLayerState(state0));
_sprite.LayerSetDirOffset(CornerLayers.NE, SpriteComponent.DirectionOffset.CounterClockwise);
_sprite.LayerMapSet(CornerLayers.NW, _sprite.AddLayerState(state0));
_sprite.LayerSetDirOffset(CornerLayers.NW, SpriteComponent.DirectionOffset.Flip);
_sprite.LayerMapSet(CornerLayers.SW, _sprite.AddLayerState(state0));
_sprite.LayerSetDirOffset(CornerLayers.SW, SpriteComponent.DirectionOffset.Clockwise);
}
public override void Shutdown()
{
_snapGrid.OnPositionChanged -= SnapGridOnPositionChanged;
base.Shutdown();
}
private void SnapGridOnPositionChanged()
{
Owner.EntityManager.RaiseEvent(Owner, new WindowSmoothDirtyEvent());
}
public void UpdateSprite()
{
var lowWall = FindLowWall();
if (lowWall == null)
{
return;
}
_sprite.LayerSetState(CornerLayers.NE, $"{_stateBase}{(int) lowWall.LastCornerNE}");
_sprite.LayerSetState(CornerLayers.SE, $"{_stateBase}{(int) lowWall.LastCornerSE}");
_sprite.LayerSetState(CornerLayers.SW, $"{_stateBase}{(int) lowWall.LastCornerSW}");
_sprite.LayerSetState(CornerLayers.NW, $"{_stateBase}{(int) lowWall.LastCornerNW}");
}
private LowWallComponent FindLowWall()
{
foreach (var entity in _snapGrid.GetLocal())
{
if (entity.TryGetComponent(out LowWallComponent lowWall))
{
return lowWall;
}
}
return null;
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _stateBase, "base", null);
}
}
}

View File

@@ -1,27 +0,0 @@
using Content.Client.GameObjects.Components.Mobs;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
namespace Content.Client.GameObjects.EntitySystems
{
public sealed class CameraRecoilSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
EntityQuery = new TypeEntityQuery(typeof(CameraRecoilComponent));
}
public override void FrameUpdate(float frameTime)
{
base.FrameUpdate(frameTime);
foreach (var entity in RelevantEntities)
{
var recoil = entity.GetComponent<CameraRecoilComponent>();
recoil.FrameUpdate(frameTime);
}
}
}
}

View File

@@ -1,75 +0,0 @@
using Content.Client.GameObjects.Components.Actor;
using Content.Client.UserInterface;
using Content.Shared.Input;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.Player;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Input;
using Robust.Shared.IoC;
namespace Content.Client.GameObjects.EntitySystems
{
public sealed class CharacterInterfaceSystem : EntitySystem
{
#pragma warning disable 649
[Dependency] private readonly IGameHud _gameHud;
[Dependency] private readonly IPlayerManager _playerManager;
#pragma warning restore 649
public override void Initialize()
{
base.Initialize();
var inputSys = EntitySystemManager.GetEntitySystem<InputSystem>();
inputSys.BindMap.BindFunction(ContentKeyFunctions.OpenCharacterMenu,
InputCmdHandler.FromDelegate(s => HandleOpenCharacterMenu()));
}
private void HandleOpenCharacterMenu()
{
if (_playerManager.LocalPlayer.ControlledEntity == null
|| !_playerManager.LocalPlayer.ControlledEntity.TryGetComponent(out CharacterInterface characterInterface))
{
return;
}
var menu = characterInterface.Window;
if (menu == null)
{
return;
}
if (menu.IsOpen)
{
if (menu.IsAtFront())
{
_setOpenValue(menu, false);
}
else
{
menu.MoveToFront();
}
}
else
{
_setOpenValue(menu, true);
}
}
private void _setOpenValue(SS14Window menu, bool value)
{
if (value)
{
_gameHud.CharacterButtonDown = true;
menu.OpenCentered();
}
else
{
_gameHud.CharacterButtonDown = false;
menu.Close();
}
}
}
}

View File

@@ -1,69 +0,0 @@
using Content.Client.UserInterface;
using Content.Shared.Input;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.Player;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Input;
using Robust.Shared.IoC;
namespace Content.Client.GameObjects.EntitySystems
{
public sealed class ClientInventorySystem : EntitySystem
{
#pragma warning disable 649
[Dependency] private readonly IGameHud _gameHud;
[Dependency] private readonly IPlayerManager _playerManager;
#pragma warning restore 649
public override void Initialize()
{
base.Initialize();
var inputSys = EntitySystemManager.GetEntitySystem<InputSystem>();
inputSys.BindMap.BindFunction(ContentKeyFunctions.OpenInventoryMenu,
InputCmdHandler.FromDelegate(s => HandleOpenInventoryMenu()));
}
private void HandleOpenInventoryMenu()
{
if (_playerManager.LocalPlayer.ControlledEntity == null
|| !_playerManager.LocalPlayer.ControlledEntity.TryGetComponent(out ClientInventoryComponent clientInventory))
{
return;
}
var menu = clientInventory.InterfaceController.Window;
if (menu.IsOpen)
{
if (menu.IsAtFront())
{
_setOpenValue(menu, false);
}
else
{
menu.MoveToFront();
}
}
else
{
_setOpenValue(menu, true);
}
}
private void _setOpenValue(SS14Window menu, bool value)
{
if (value)
{
_gameHud.InventoryButtonDown = true;
menu.OpenCentered();
}
else
{
_gameHud.InventoryButtonDown = false;
menu.Close();
}
}
}
}

View File

@@ -1,7 +0,0 @@
namespace Content.Client.GameObjects.EntitySystems
{
public class ClientNotifySystem
{
}
}

View File

@@ -1,70 +0,0 @@
using Content.Client.Construction;
using Content.Client.GameObjects.Components.Construction;
using Content.Client.UserInterface;
using Content.Shared.Input;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.Player;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Input;
using Robust.Shared.IoC;
namespace Content.Client.GameObjects.EntitySystems
{
public sealed class ConstructorSystem : EntitySystem
{
#pragma warning disable 649
[Dependency] private readonly IGameHud _gameHud;
[Dependency] private readonly IPlayerManager _playerManager;
#pragma warning restore 649
public override void Initialize()
{
base.Initialize();
var inputSys = EntitySystemManager.GetEntitySystem<InputSystem>();
inputSys.BindMap.BindFunction(ContentKeyFunctions.OpenCraftingMenu,
new PointerInputCmdHandler(HandleOpenCraftingMenu));
}
private void HandleOpenCraftingMenu(in PointerInputCmdHandler.PointerInputCmdArgs args)
{
if (_playerManager.LocalPlayer.ControlledEntity == null
|| !_playerManager.LocalPlayer.ControlledEntity.TryGetComponent(out ConstructorComponent constructor))
{
return;
}
var menu = constructor.ConstructionMenu;
if (menu.IsOpen)
{
if (menu.IsAtFront())
{
_setOpenValue(menu, false);
}
else
{
menu.MoveToFront();
}
}
else
{
_setOpenValue(menu, true);
}
}
private void _setOpenValue(ConstructionMenu menu, bool value)
{
if (value)
{
_gameHud.CraftingButtonDown = true;
menu.OpenCentered();
}
else
{
_gameHud.CraftingButtonDown = false;
menu.Close();
}
}
}
}

View File

@@ -1,149 +0,0 @@
using System.Threading;
using System.Threading.Tasks;
using Content.Shared.GameObjects.EntitySystemMessages;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Input;
using JetBrains.Annotations;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Players;
namespace Content.Client.GameObjects.EntitySystems
{
[UsedImplicitly]
internal sealed class ExamineSystem : ExamineSystemShared
{
public const string StyleClassEntityTooltip = "entity-tooltip";
#pragma warning disable 649
[Dependency] private IInputManager _inputManager;
[Dependency] private IUserInterfaceManager _userInterfaceManager;
[Dependency] private IEntityManager _entityManager;
[Dependency] private IPlayerManager _playerManager;
#pragma warning restore 649
private Popup _examineTooltipOpen;
private CancellationTokenSource _requestCancelTokenSource;
public override void Initialize()
{
IoCManager.InjectDependencies(this);
var inputSys = EntitySystemManager.GetEntitySystem<InputSystem>();
inputSys.BindMap.BindFunction(ContentKeyFunctions.ExamineEntity, new PointerInputCmdHandler(HandleExamine));
}
public override void RegisterMessageTypes()
{
base.RegisterMessageTypes();
RegisterMessageType<ExamineSystemMessages.ExamineInfoResponseMessage>();
}
private void HandleExamine(ICommonSession session, GridCoordinates coords, EntityUid uid)
{
if (!uid.IsValid() || !_entityManager.TryGetEntity(uid, out var examined))
{
return;
}
var playerEntity = _playerManager.LocalPlayer.ControlledEntity;
if (playerEntity == null || !CanExamine(playerEntity, examined))
{
return;
}
DoExamine(examined);
}
public async void DoExamine(IEntity entity)
{
CloseTooltip();
var mousePos = _inputManager.MouseScreenPosition;
// Actually open the tooltip.
_examineTooltipOpen = new Popup();
_userInterfaceManager.StateRoot.AddChild(_examineTooltipOpen);
var panel = new PanelContainer();
panel.AddStyleClass(StyleClassEntityTooltip);
panel.ModulateSelfOverride = Color.LightGray.WithAlpha(0.90f);
_examineTooltipOpen.AddChild(panel);
panel.SetAnchorAndMarginPreset(Control.LayoutPreset.Wide);
var vBox = new VBoxContainer();
panel.AddChild(vBox);
var hBox = new HBoxContainer { SeparationOverride = 5};
vBox.AddChild(hBox);
if (entity.TryGetComponent(out ISpriteComponent sprite))
{
hBox.AddChild(new SpriteView {Sprite = sprite});
}
hBox.AddChild(new Label
{
Text = entity.Name,
SizeFlagsHorizontal = Control.SizeFlags.FillExpand,
});
const float minWidth = 300;
var size = Vector2.ComponentMax((minWidth, 0), panel.CombinedMinimumSize);
_examineTooltipOpen.Open(UIBox2.FromDimensions(mousePos, size));
if (entity.Uid.IsClientSide())
{
return;
}
// Ask server for extra examine info.
RaiseNetworkEvent(new ExamineSystemMessages.RequestExamineInfoMessage(entity.Uid));
ExamineSystemMessages.ExamineInfoResponseMessage response;
try
{
_requestCancelTokenSource = new CancellationTokenSource();
response =
await AwaitNetMessage<ExamineSystemMessages.ExamineInfoResponseMessage>(_requestCancelTokenSource
.Token);
}
catch (TaskCanceledException)
{
return;
}
finally
{
_requestCancelTokenSource = null;
}
var richLabel = new RichTextLabel();
richLabel.SetMessage(response.Message);
vBox.AddChild(richLabel);
}
public void CloseTooltip()
{
if (_examineTooltipOpen != null)
{
_examineTooltipOpen.Dispose();
_examineTooltipOpen = null;
}
if (_requestCancelTokenSource != null)
{
_requestCancelTokenSource.Cancel();
_requestCancelTokenSource = null;
}
}
}
}

View File

@@ -1,155 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Content.Client.GameObjects.Components.IconSmoothing;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
namespace Content.Client.GameObjects.EntitySystems
{
/// <summary>
/// Entity system implementing the logic for <see cref="IconSmoothComponent"/>
/// </summary>
[UsedImplicitly]
internal sealed class IconSmoothSystem : EntitySystem
{
#pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager;
#pragma warning restore 649
private readonly Queue<IEntity> _dirtyEntities = new Queue<IEntity>();
private int _generation;
public override void SubscribeEvents()
{
base.SubscribeEvents();
SubscribeEvent<IconSmoothDirtyEvent>(HandleDirtyEvent);
}
public override void Initialize()
{
base.Initialize();
IoCManager.InjectDependencies(this);
}
public override void FrameUpdate(float frameTime)
{
base.FrameUpdate(frameTime);
if (_dirtyEntities.Count == 0)
{
return;
}
_generation += 1;
// Performance: This could be spread over multiple updates, or made parallel.
while (_dirtyEntities.Count > 0)
{
CalculateNewSprite(_dirtyEntities.Dequeue());
}
}
private void HandleDirtyEvent(object sender, IconSmoothDirtyEvent ev)
{
// Yes, we updates ALL smoothing entities surrounding us even if they would never smooth with us.
// This is simpler to implement. If you want to optimize it be my guest.
if (sender is IEntity senderEnt && senderEnt.IsValid() &&
senderEnt.HasComponent<IconSmoothComponent>())
{
var snapGrid = senderEnt.GetComponent<SnapGridComponent>();
_dirtyEntities.Enqueue(senderEnt);
AddValidEntities(snapGrid.GetInDir(Direction.North));
AddValidEntities(snapGrid.GetInDir(Direction.South));
AddValidEntities(snapGrid.GetInDir(Direction.East));
AddValidEntities(snapGrid.GetInDir(Direction.West));
if (ev.Mode == IconSmoothingMode.Corners)
{
AddValidEntities(snapGrid.GetInDir(Direction.NorthEast));
AddValidEntities(snapGrid.GetInDir(Direction.SouthEast));
AddValidEntities(snapGrid.GetInDir(Direction.SouthWest));
AddValidEntities(snapGrid.GetInDir(Direction.NorthWest));
}
}
else if (ev.LastPosition.HasValue)
{
// Entity is no longer valid, update around the last position it was at.
var grid = _mapManager.GetGrid(ev.LastPosition.Value.grid);
var pos = ev.LastPosition.Value.pos;
AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(1, 0), ev.Offset));
AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(-1, 0), ev.Offset));
AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(0, 1), ev.Offset));
AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(0, -1), ev.Offset));
if (ev.Mode == IconSmoothingMode.Corners)
{
AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(1, 1), ev.Offset));
AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(-1, -1), ev.Offset));
AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(-1, 1), ev.Offset));
AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(1, -1), ev.Offset));
}
}
}
private void AddValidEntities(IEnumerable<IEntity> candidates)
{
foreach (var entity in candidates)
{
if (entity.HasComponent<IconSmoothComponent>())
{
_dirtyEntities.Enqueue(entity);
}
}
}
private void AddValidEntities(IEnumerable<IComponent> candidates)
{
AddValidEntities(candidates.Select(c => c.Owner));
}
private void CalculateNewSprite(IEntity entity)
{
// The generation check prevents updating an entity multiple times per tick.
// As it stands now, it's totally possible for something to get queued twice.
// Generation on the component is set after an update so we can cull updates that happened this generation.
if (!entity.IsValid()
|| !entity.TryGetComponent(out IconSmoothComponent smoothing)
|| smoothing.UpdateGeneration == _generation)
{
return;
}
smoothing.CalculateNewSprite();
smoothing.UpdateGeneration = _generation;
}
}
/// <summary>
/// Event raised by a <see cref="IconSmoothComponent"/> when it needs to be recalculated.
/// </summary>
public sealed class IconSmoothDirtyEvent : EntitySystemMessage
{
public IconSmoothDirtyEvent((GridId grid, MapIndices pos)? lastPosition, SnapGridOffset offset, IconSmoothingMode mode)
{
LastPosition = lastPosition;
Offset = offset;
Mode = mode;
}
public (GridId grid, MapIndices pos)? LastPosition { get; }
public SnapGridOffset Offset { get; }
public IconSmoothingMode Mode { get; }
}
}

View File

@@ -1,76 +0,0 @@
using Content.Client.GameObjects.Components.Weapons.Ranged;
using Content.Client.Interfaces.GameObjects;
using Content.Shared.Input;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Input;
using Robust.Client.Player;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Input;
using Robust.Shared.IoC;
namespace Content.Client.GameObjects.EntitySystems
{
public class RangedWeaponSystem : EntitySystem
{
#pragma warning disable 649
[Dependency] private readonly IPlayerManager _playerManager;
[Dependency] private readonly IEyeManager _eyeManager;
[Dependency] private readonly IInputManager _inputManager;
#pragma warning restore 649
private InputSystem _inputSystem;
private bool _isFirstShot;
private bool _blocked;
public override void Initialize()
{
base.Initialize();
IoCManager.InjectDependencies(this);
_inputSystem = EntitySystemManager.GetEntitySystem<InputSystem>();
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var canFireSemi = _isFirstShot;
var state = _inputSystem.CmdStates.GetState(ContentKeyFunctions.UseItemInHand);
if (state != BoundKeyState.Down)
{
_isFirstShot = true;
_blocked = false;
return;
}
_isFirstShot = false;
var entity = _playerManager.LocalPlayer.ControlledEntity;
if (entity == null || !entity.TryGetComponent(out IHandsComponent hands))
{
return;
}
var held = hands.ActiveHand;
if (held == null || !held.TryGetComponent(out ClientRangedWeaponComponent weapon))
{
_blocked = true;
return;
}
if (_blocked)
{
return;
}
var worldPos = _eyeManager.ScreenToWorld(_inputManager.MouseScreenPosition);
if (weapon.Automatic || canFireSemi)
{
weapon.TryFire(worldPos);
}
}
}
}

View File

@@ -1,80 +0,0 @@
using Content.Client.GameObjects.Components;
using Content.Shared.Maps;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Content.Client.GameObjects.EntitySystems
{
/// <summary>
/// Entity system backing <see cref="SubFloorHideComponent"/>.
/// </summary>
internal sealed class SubFloorHideSystem : EntitySystem
{
#pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager;
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager;
#pragma warning restore 649
public override void Initialize()
{
base.Initialize();
IoCManager.InjectDependencies(this);
_mapManager.GridChanged += MapManagerOnGridChanged;
_mapManager.TileChanged += MapManagerOnTileChanged;
SubscribeEvent<SubFloorHideDirtyEvent>(HandleDirtyEvent);
}
private void HandleDirtyEvent(object sender, SubFloorHideDirtyEvent ev)
{
if (!(sender is IEntity senderEnt))
{
return;
}
var sprite = senderEnt.GetComponent<ISpriteComponent>();
var grid = _mapManager.GetGrid(senderEnt.Transform.GridID);
var position = senderEnt.Transform.GridPosition;
var tileRef = grid.GetTileRef(position);
var tileDef = (ContentTileDefinition) _tileDefinitionManager[tileRef.Tile.TypeId];
sprite.Visible = tileDef.IsSubFloor;
}
private void MapManagerOnTileChanged(object sender, TileChangedEventArgs e)
{
UpdateTile(_mapManager.GetGrid(e.NewTile.GridIndex), e.NewTile.GridIndices);
}
private void MapManagerOnGridChanged(object sender, GridChangedEventArgs e)
{
foreach (var modified in e.Modified)
{
UpdateTile(e.Grid, modified.position);
}
}
private void UpdateTile(IMapGrid grid, MapIndices position)
{
var tile = grid.GetTileRef(position);
var tileDef = (ContentTileDefinition) _tileDefinitionManager[tile.Tile.TypeId];
foreach (var snapGridComponent in grid.GetSnapGridCell(position, SnapGridOffset.Center))
{
var entity = snapGridComponent.Owner;
if (!entity.HasComponent<SubFloorHideComponent>() ||
!entity.TryGetComponent(out ISpriteComponent spriteComponent))
{
continue;
}
spriteComponent.Visible = tileDef.IsSubFloor;
}
}
}
}

View File

@@ -1,235 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.EntitySystemMessages;
using Content.Shared.Input;
using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.State;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
using Robust.Client.State.States;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Input;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
namespace Content.Client.GameObjects.EntitySystems
{
public class VerbSystem : EntitySystem
{
#pragma warning disable 649
[Dependency] private readonly IStateManager _stateManager;
[Dependency] private readonly IEntityManager _entityManager;
[Dependency] private readonly IPlayerManager _playerManager;
[Dependency] private readonly IInputManager _inputManager;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
#pragma warning restore 649
private Popup _currentPopup;
private EntityUid _currentEntity;
public override void Initialize()
{
base.Initialize();
IoCManager.InjectDependencies(this);
var input = EntitySystemManager.GetEntitySystem<InputSystem>();
input.BindMap.BindFunction(ContentKeyFunctions.OpenContextMenu,
new PointerInputCmdHandler(OnOpenContextMenu));
}
public override void RegisterMessageTypes()
{
base.RegisterMessageTypes();
RegisterMessageType<VerbSystemMessages.VerbsResponseMessage>();
}
public void OpenContextMenu(IEntity entity, ScreenCoordinates screenCoordinates)
{
if (_currentPopup != null)
{
_closeContextMenu();
}
_currentEntity = entity.Uid;
_currentPopup = new Popup();
_currentPopup.UserInterfaceManager.StateRoot.AddChild(_currentPopup);
_currentPopup.OnPopupHide += _closeContextMenu;
var vBox = new VBoxContainer("ButtonBox");
_currentPopup.AddChild(vBox);
vBox.AddChild(new Label {Text = "Waiting on Server..."});
RaiseNetworkEvent(new VerbSystemMessages.RequestVerbsMessage(_currentEntity));
var size = vBox.CombinedMinimumSize;
var box = UIBox2.FromDimensions(screenCoordinates.Position, size);
_currentPopup.Open(box);
}
private void OnOpenContextMenu(in PointerInputCmdHandler.PointerInputCmdArgs args)
{
if (_currentPopup != null)
{
_closeContextMenu();
return;
}
if (!(_stateManager.CurrentState is GameScreen gameScreen))
{
return;
}
var entities = gameScreen.GetEntitiesUnderPosition(args.Coordinates);
_currentPopup = new Popup();
_currentPopup.OnPopupHide += _closeContextMenu;
var vBox = new VBoxContainer("ButtonBox");
_currentPopup.AddChild(vBox);
foreach (var entity in entities)
{
var button = new Button {Text = entity.Name};
vBox.AddChild(button);
button.OnPressed += _ => OnContextButtonPressed(entity);
}
_currentPopup.UserInterfaceManager.StateRoot.AddChild(_currentPopup);
var size = vBox.CombinedMinimumSize;
var box = UIBox2.FromDimensions(args.ScreenCoordinates.Position, size);
_currentPopup.Open(box);
}
private void OnContextButtonPressed(IEntity entity)
{
OpenContextMenu(entity, new ScreenCoordinates(_inputManager.MouseScreenPosition));
}
public override void HandleNetMessage(INetChannel channel, EntitySystemMessage message)
{
base.HandleNetMessage(channel, message);
switch (message)
{
case VerbSystemMessages.VerbsResponseMessage resp:
_fillEntityPopup(resp);
break;
}
}
private void _fillEntityPopup(VerbSystemMessages.VerbsResponseMessage msg)
{
if (_currentEntity != msg.Entity || !_entityManager.TryGetEntity(_currentEntity, out var entity))
{
return;
}
DebugTools.AssertNotNull(_currentPopup);
var buttons = new List<Button>();
var vBox = _currentPopup.GetChild<VBoxContainer>("ButtonBox");
vBox.DisposeAllChildren();
foreach (var data in msg.Verbs)
{
var button = new Button {Text = data.Text, Disabled = !data.Available};
if (data.Available)
{
button.OnPressed += _ =>
{
RaiseNetworkEvent(new VerbSystemMessages.UseVerbMessage(_currentEntity, data.Key));
_closeContextMenu();
};
}
buttons.Add(button);
}
var user = GetUserEntity();
foreach (var (component, verb) in VerbUtility.GetVerbs(entity))
{
if (verb.RequireInteractionRange)
{
var distanceSquared = (user.Transform.WorldPosition - entity.Transform.WorldPosition)
.LengthSquared;
if (distanceSquared > Verb.InteractionRangeSquared)
{
continue;
}
}
var disabled = verb.GetVisibility(user, component) != VerbVisibility.Visible;
var button = new Button
{
Text = verb.GetText(user, component),
Disabled = disabled
};
if (!disabled)
{
button.OnPressed += _ =>
{
_closeContextMenu();
try
{
verb.Activate(user, component);
}
catch (Exception e)
{
Logger.ErrorS("verb", "Exception in verb {0} on {1}:\n{2}", verb, entity, e);
}
};
}
buttons.Add(button);
}
if (buttons.Count > 0)
{
buttons.Sort((a, b) => string.Compare(a.Text, b.Text, StringComparison.Ordinal));
foreach (var button in buttons)
{
vBox.AddChild(button);
}
}
else
{
var panel = new PanelContainer();
panel.AddChild(new Label {Text = "No verbs!"});
vBox.AddChild(panel);
}
_currentPopup.Size = vBox.CombinedMinimumSize;
// If we're at the bottom of the window and the menu would go below the bottom of the window,
// shift it up so it extends UP.
var bottomCoord = vBox.CombinedMinimumSize.Y + _currentPopup.Position.Y;
if (bottomCoord > _userInterfaceManager.StateRoot.Size.Y)
{
_currentPopup.Position = _currentPopup.Position - new Vector2(0, vBox.CombinedMinimumSize.Y);
}
}
private void _closeContextMenu()
{
_currentPopup?.Dispose();
_currentPopup = null;
_currentEntity = EntityUid.Invalid;
}
private IEntity GetUserEntity()
{
return _playerManager.LocalPlayer.ControlledEntity;
}
}
}

View File

@@ -1,51 +0,0 @@
using System.Collections.Generic;
using Content.Client.GameObjects.Components;
using Content.Client.GameObjects.Components.IconSmoothing;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Map;
namespace Content.Client.GameObjects.EntitySystems
{
[UsedImplicitly]
public sealed class WindowSystem : EntitySystem
{
private readonly Queue<IEntity> _dirtyEntities = new Queue<IEntity>();
public override void Initialize()
{
base.Initialize();
SubscribeEvent<WindowSmoothDirtyEvent>(HandleDirtyEvent);
}
private void HandleDirtyEvent(object sender, WindowSmoothDirtyEvent ev)
{
if (sender is IEntity senderEnt && senderEnt.HasComponent<WindowComponent>())
{
_dirtyEntities.Enqueue(senderEnt);
}
}
public override void FrameUpdate(float frameTime)
{
base.FrameUpdate(frameTime);
// Performance: This could be spread over multiple updates, or made parallel.
while (_dirtyEntities.Count > 0)
{
_dirtyEntities.Dequeue().GetComponent<WindowComponent>().UpdateSprite();
}
}
}
/// <summary>
/// Event raised by a <see cref="WindowComponent"/> when it needs to be recalculated.
/// </summary>
public sealed class WindowSmoothDirtyEvent : EntitySystemMessage
{
}
}

View File

@@ -1,270 +0,0 @@
using System;
using System.Linq;
using Content.Client.Chat;
using Content.Client.Interfaces;
using Content.Client.Interfaces.Chat;
using Content.Client.UserInterface;
using Content.Shared;
using Content.Shared.Input;
using Robust.Client;
using Robust.Client.Console;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Shared.Input;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Content.Client.GameTicking
{
public class ClientGameTicker : SharedGameTicker, IClientGameTicker
{
#pragma warning disable 649
[Dependency] private IClientNetManager _netManager;
[Dependency] private IUserInterfaceManager _userInterfaceManager;
[Dependency] private IInputManager _inputManager;
[Dependency] private IBaseClient _baseClient;
[Dependency] private IChatManager _chatManager;
[Dependency] private IClientConsole _console;
[Dependency] private ILocalizationManager _localization;
[Dependency] private IResourceCache _resourceCache;
[Dependency] private IPlayerManager _playerManager;
[Dependency] private IGameHud _gameHud;
#pragma warning restore 649
[ViewVariables] private bool _areWeReady;
[ViewVariables] private bool _initialized;
[ViewVariables] private TickerState _tickerState;
[ViewVariables] private ChatBox _gameChat;
[ViewVariables] private LobbyGui _lobby;
[ViewVariables] private bool _gameStarted;
[ViewVariables] private DateTime _startTime;
public void Initialize()
{
DebugTools.Assert(!_initialized);
_netManager.RegisterNetMessage<MsgTickerJoinLobby>(nameof(MsgTickerJoinLobby), _joinLobby);
_netManager.RegisterNetMessage<MsgTickerJoinGame>(nameof(MsgTickerJoinGame), _joinGame);
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus), _lobbyStatus);
_baseClient.RunLevelChanged += BaseClientOnRunLevelChanged;
_playerManager.PlayerListUpdated += PlayerManagerOnPlayerListUpdated;
_initialized = true;
}
private void PlayerManagerOnPlayerListUpdated(object sender, EventArgs e)
{
if (_lobby == null)
{
return;
}
_updatePlayerList();
}
private void _updatePlayerList()
{
_lobby.OnlinePlayerItemList.Clear();
foreach (var session in _playerManager.Sessions.OrderBy(s => s.Name))
{
_lobby.OnlinePlayerItemList.AddItem(session.Name);
}
}
private void BaseClientOnRunLevelChanged(object sender, RunLevelChangedEventArgs e)
{
if (e.NewLevel != ClientRunLevel.Initialize)
{
return;
}
_tickerState = TickerState.Unset;
_lobby?.Dispose();
_lobby = null;
_gameChat?.Dispose();
_gameChat = null;
_gameHud.RootControl.Orphan();
}
public void FrameUpdate(RenderFrameEventArgs renderFrameEventArgs)
{
if (_lobby == null)
{
return;
}
if (_gameStarted)
{
_lobby.StartTime.Text = "";
return;
}
string text;
var difference = _startTime - DateTime.UtcNow;
if (difference.Ticks < 0)
{
if (difference.TotalSeconds < -5)
{
text = _localization.GetString("Right Now?");
}
else
{
text = _localization.GetString("Right Now");
}
}
else
{
text = $"{(int) Math.Floor(difference.TotalMinutes)}:{difference.Seconds:D2}";
}
_lobby.StartTime.Text = _localization.GetString("Round Starts In: {0}", text);
}
private void _lobbyStatus(MsgTickerLobbyStatus message)
{
_startTime = message.StartTime;
_gameStarted = message.IsRoundStarted;
_areWeReady = message.YouAreReady;
_updateLobbyUi();
}
private void _updateLobbyUi()
{
if (_lobby == null)
{
return;
}
if (_gameStarted)
{
_lobby.ReadyButton.Text = _localization.GetString("Join");
_lobby.ReadyButton.ToggleMode = false;
_lobby.ReadyButton.Pressed = false;
}
else
{
_lobby.StartTime.Text = "";
_lobby.ReadyButton.Text = _localization.GetString("Ready Up");
_lobby.ReadyButton.ToggleMode = true;
_lobby.ReadyButton.Pressed = _areWeReady;
}
}
private void _joinLobby(MsgTickerJoinLobby message)
{
if (_tickerState == TickerState.InLobby)
{
return;
}
if (_gameChat != null)
{
_gameChat.Dispose();
_gameChat = null;
}
_gameHud.RootControl.Orphan();
_tickerState = TickerState.InLobby;
_lobby = new LobbyGui(_localization, _resourceCache);
_userInterfaceManager.StateRoot.AddChild(_lobby);
_lobby.SetAnchorAndMarginPreset(Control.LayoutPreset.Wide, margin: 20);
_chatManager.SetChatBox(_lobby.Chat);
_lobby.Chat.DefaultChatFormat = "ooc \"{0}\"";
_lobby.ServerName.Text = _baseClient.GameInfo.ServerName;
_inputManager.SetInputCommand(ContentKeyFunctions.FocusChat,
InputCmdHandler.FromDelegate(session =>
{
_lobby.Chat.Input.IgnoreNext = true;
_lobby.Chat.Input.GrabKeyboardFocus();
}));
_updateLobbyUi();
_lobby.ObserveButton.OnPressed += args => _console.ProcessCommand("observe");
_lobby.ReadyButton.OnPressed += args =>
{
if (!_gameStarted)
{
return;
}
_console.ProcessCommand("joingame");
};
_lobby.ReadyButton.OnToggled += args =>
{
if (_gameStarted)
{
return;
}
_console.ProcessCommand($"toggleready {args.Pressed}");
};
_lobby.LeaveButton.OnPressed += args => _console.ProcessCommand("disconnect");
_updatePlayerList();
}
private void _joinGame(MsgTickerJoinGame message)
{
if (_tickerState == TickerState.InGame)
{
return;
}
_tickerState = TickerState.InGame;
if (_lobby != null)
{
_lobby.Dispose();
_lobby = null;
}
_inputManager.SetInputCommand(ContentKeyFunctions.FocusChat,
InputCmdHandler.FromDelegate(session =>
{
_gameChat.Input.IgnoreNext = true;
_gameChat.Input.GrabKeyboardFocus();
}));
_gameChat = new ChatBox();
_userInterfaceManager.StateRoot.AddChild(_gameChat);
_userInterfaceManager.StateRoot.AddChild(_gameHud.RootControl);
_chatManager.SetChatBox(_gameChat);
_gameChat.DefaultChatFormat = "say \"{0}\"";
_gameChat.Input.PlaceHolder = _localization.GetString("Say something! [ for OOC");
}
private enum TickerState
{
Unset = 0,
/// <summary>
/// The client is in the lobby.
/// </summary>
InLobby = 1,
/// <summary>
/// The client is NOT in the lobby.
/// Do not confuse this with the client session status.
/// </summary>
InGame = 2
}
}
}

View File

@@ -1,34 +0,0 @@
using Robust.Client.Graphics.Drawing;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Graphics.Shaders;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.Graphics.Overlays
{
public class CircleMaskOverlay : Overlay
{
#pragma warning disable 649
[Dependency] private readonly IPrototypeManager _prototypeManager;
[Dependency] private readonly IEyeManager _eyeManager;
#pragma warning restore 649
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public CircleMaskOverlay() : base(nameof(CircleMaskOverlay))
{
IoCManager.InjectDependencies(this);
Shader = _prototypeManager.Index<ShaderPrototype>("circlemask").Instance();
}
protected override void Draw(DrawingHandleBase handle)
{
var worldHandle = (DrawingHandleWorld)handle;
var viewport = _eyeManager.GetWorldViewport();
worldHandle.DrawRect(viewport, Color.White);
}
}
}

View File

@@ -1,33 +0,0 @@
using Robust.Client.Graphics.Drawing;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Graphics.Shaders;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.Graphics.Overlays
{
public class GradientCircleMask : Overlay
{
#pragma warning disable 649
[Dependency] private readonly IPrototypeManager _prototypeManager;
[Dependency] private readonly IEyeManager _eyeManager;
#pragma warning restore 649
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public GradientCircleMask() : base(nameof(GradientCircleMask))
{
IoCManager.InjectDependencies(this);
Shader = _prototypeManager.Index<ShaderPrototype>("gradientcirclemask").Instance();
}
protected override void Draw(DrawingHandleBase handle)
{
var worldHandle = (DrawingHandleWorld)handle;
var viewport = _eyeManager.GetWorldViewport();
worldHandle.DrawRect(viewport, Color.White);
}
}
}

View File

@@ -1,42 +0,0 @@
using Content.Shared.Input;
using Robust.Shared.Input;
namespace Content.Client.Input
{
/// <summary>
/// Contains a helper function for setting up all content
/// contexts, and modifying existing engine ones.
/// </summary>
public static class ContentContexts
{
public static void SetupContexts(IInputContextContainer contexts)
{
var common = contexts.GetContext("common");
common.AddFunction(ContentKeyFunctions.FocusChat);
common.AddFunction(ContentKeyFunctions.ExamineEntity);
common.AddFunction(ContentKeyFunctions.OpenTutorial);
var human = contexts.GetContext("human");
human.AddFunction(ContentKeyFunctions.SwapHands);
human.AddFunction(ContentKeyFunctions.Drop);
human.AddFunction(ContentKeyFunctions.ActivateItemInHand);
human.AddFunction(ContentKeyFunctions.OpenCharacterMenu);
human.AddFunction(ContentKeyFunctions.UseItemInHand);
human.AddFunction(ContentKeyFunctions.ActivateItemInWorld);
human.AddFunction(ContentKeyFunctions.ThrowItemInHand);
human.AddFunction(ContentKeyFunctions.OpenContextMenu);
human.AddFunction(ContentKeyFunctions.OpenCraftingMenu);
human.AddFunction(ContentKeyFunctions.OpenInventoryMenu);
// Disabled until there is feedback, so hitting tab doesn't suddenly break interaction.
// human.AddFunction(ContentKeyFunctions.ToggleCombatMode);
var ghost = contexts.New("ghost", "common");
ghost.AddFunction(EngineKeyFunctions.MoveUp);
ghost.AddFunction(EngineKeyFunctions.MoveDown);
ghost.AddFunction(EngineKeyFunctions.MoveLeft);
ghost.AddFunction(EngineKeyFunctions.MoveRight);
ghost.AddFunction(EngineKeyFunctions.Run);
ghost.AddFunction(ContentKeyFunctions.OpenContextMenu);
}
}
}

View File

@@ -1,17 +0,0 @@
using Content.Client.Chat;
using Robust.Client;
using Robust.Shared.GameObjects;
namespace Content.Client.Interfaces.Chat
{
public interface IChatManager
{
void Initialize();
void FrameUpdate(RenderFrameEventArgs delta);
void SetChatBox(ChatBox chatBox);
void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble);
}
}

View File

@@ -1,4 +1,4 @@
using Robust.Shared.Interfaces.GameObjects;
using SS14.Shared.Interfaces.GameObjects;
namespace Content.Client.Interfaces.GameObjects
{
@@ -8,9 +8,7 @@ namespace Content.Client.Interfaces.GameObjects
{
IEntity GetEntity(string index);
string ActiveIndex { get; }
IEntity ActiveHand { get; }
void SendChangeHand(string index);
void AttackByInHand(string index);
}
}

View File

@@ -1,11 +0,0 @@
using Content.Client.UserInterface;
using Robust.Client;
namespace Content.Client.Interfaces
{
public interface IClientGameTicker
{
void Initialize();
void FrameUpdate(RenderFrameEventArgs renderFrameEventArgs);
}
}

View File

@@ -1,14 +0,0 @@
using Content.Shared.Interfaces;
using Robust.Client;
using Robust.Shared.Map;
namespace Content.Client.Interfaces
{
public interface IClientNotifyManager : ISharedNotifyManager
{
void Initialize();
void PopupMessage(ScreenCoordinates coordinates, string message);
void PopupMessage(string message);
void FrameUpdate(RenderFrameEventArgs eventArgs);
}
}

View File

@@ -1,12 +0,0 @@
using System;
using Robust.Client.Graphics;
namespace Content.Client.Interfaces.Parallax
{
public interface IParallaxManager
{
event Action<Texture> OnTextureLoaded;
Texture ParallaxTexture { get; }
void LoadParallax();
}
}

View File

@@ -1,418 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Nett;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
using Robust.Client.Utility;
using Robust.Shared.Interfaces.Log;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Noise;
using BlendFactor = Robust.Shared.Maths.Color.BlendFactor;
namespace Content.Client.Parallax
{
public class ParallaxGenerator
{
private readonly List<Layer> Layers = new List<Layer>();
public static Image<Rgba32> GenerateParallax(TomlTable config, Size size, ISawmill sawmill)
{
sawmill.Debug("Generating parallax!");
var generator = new ParallaxGenerator();
generator._loadConfig(config);
var image = new Image<Rgba32>(Configuration.Default, size.Width, size.Height, Rgba32.Black);
var count = 0;
foreach (var layer in generator.Layers)
{
layer.Apply(image);
sawmill.Debug("Layer {0} done!", count++);
}
return image;
}
private void _loadConfig(TomlTable config)
{
foreach (var layerArray in config.Get<TomlTableArray>("layers").Items)
{
var layer = layerArray.Get<TomlTable>();
switch (layer.Get<string>("type"))
{
case "noise":
var layerNoise = new LayerNoise(layer);
Layers.Add(layerNoise);
break;
case "points":
var layerPoint = new LayerPoints(layer);
Layers.Add(layerPoint);
break;
default:
throw new NotSupportedException();
}
}
}
private abstract class Layer
{
public abstract void Apply(Image<Rgba32> bitmap);
}
private class LayerNoise : Layer
{
private readonly Color InnerColor = Color.White;
private readonly Color OuterColor = Color.Black;
private readonly NoiseGenerator.NoiseType NoiseType = NoiseGenerator.NoiseType.Fbm;
private readonly uint Seed = 1234;
private readonly double Persistence = 0.5;
private readonly double Lacunarity = Math.PI * 2 / 3;
private readonly double Frequency = 1;
private readonly uint Octaves = 3;
private readonly double Threshold;
private readonly double Power = 1;
private readonly BlendFactor SrcFactor = BlendFactor.One;
private readonly BlendFactor DstFactor = BlendFactor.One;
public LayerNoise(TomlTable table)
{
if (table.TryGetValue("innercolor", out var tomlObject))
{
InnerColor = Color.FromHex(tomlObject.Get<string>());
}
if (table.TryGetValue("outercolor", out tomlObject))
{
OuterColor = Color.FromHex(tomlObject.Get<string>());
}
if (table.TryGetValue("seed", out tomlObject))
{
Seed = (uint) tomlObject.Get<int>();
}
if (table.TryGetValue("persistence", out tomlObject))
{
Persistence = double.Parse(tomlObject.Get<string>(), CultureInfo.InvariantCulture);
}
if (table.TryGetValue("lacunarity", out tomlObject))
{
Lacunarity = double.Parse(tomlObject.Get<string>(), CultureInfo.InvariantCulture);
}
if (table.TryGetValue("frequency", out tomlObject))
{
Frequency = double.Parse(tomlObject.Get<string>(), CultureInfo.InvariantCulture);
}
if (table.TryGetValue("octaves", out tomlObject))
{
Octaves = (uint) tomlObject.Get<int>();
}
if (table.TryGetValue("threshold", out tomlObject))
{
Threshold = double.Parse(tomlObject.Get<string>(), CultureInfo.InvariantCulture);
}
if (table.TryGetValue("sourcefactor", out tomlObject))
{
SrcFactor = (BlendFactor) Enum.Parse(typeof(BlendFactor), tomlObject.Get<string>());
}
if (table.TryGetValue("destfactor", out tomlObject))
{
DstFactor = (BlendFactor) Enum.Parse(typeof(BlendFactor), tomlObject.Get<string>());
}
if (table.TryGetValue("power", out tomlObject))
{
Power = double.Parse(tomlObject.Get<string>(), CultureInfo.InvariantCulture);
}
if (table.TryGetValue("noise_type", out tomlObject))
{
switch (tomlObject.Get<string>())
{
case "fbm":
NoiseType = NoiseGenerator.NoiseType.Fbm;
break;
case "ridged":
NoiseType = NoiseGenerator.NoiseType.Ridged;
break;
default:
throw new InvalidOperationException();
}
}
}
public override void Apply(Image<Rgba32> bitmap)
{
var noise = new NoiseGenerator(NoiseType);
noise.SetSeed(Seed);
noise.SetFrequency(Frequency);
noise.SetPersistence(Persistence);
noise.SetLacunarity(Lacunarity);
noise.SetOctaves(Octaves);
noise.SetPeriodX(bitmap.Width);
noise.SetPeriodY(bitmap.Height);
var threshVal = 1 / (1 - Threshold);
var powFactor = 1 / Power;
for (var x = 0; x < bitmap.Width; x++)
{
for (var y = 0; y < bitmap.Height; y++)
{
// Do noise calculations.
var noiseVal = Math.Min(1, Math.Max(0, (noise.GetNoiseTiled(x, y) + 1) / 2));
// Threshold
noiseVal = Math.Max(0, noiseVal - Threshold);
noiseVal *= threshVal;
noiseVal = Math.Pow(noiseVal, powFactor);
// Get colors based on noise values.
var srcColor = Color.InterpolateBetween(InnerColor, OuterColor, (float) noiseVal)
.WithAlpha((float) noiseVal);
// Apply blending factors & write back.
var dstColor = bitmap[x, y].ConvertImgSharp();
bitmap[x, y] = Color.Blend(dstColor, srcColor, DstFactor, SrcFactor).ConvertImgSharp();
}
}
}
}
private class LayerPoints : Layer
{
private readonly int Seed = 1234;
private readonly int PointCount = 100;
private readonly Color CloseColor = Color.White;
private readonly Color FarColor = Color.Black;
private readonly BlendFactor SrcFactor = BlendFactor.One;
private readonly BlendFactor DstFactor = BlendFactor.One;
// Noise mask stuff.
private readonly bool Masked;
private readonly NoiseGenerator.NoiseType MaskNoiseType = NoiseGenerator.NoiseType.Fbm;
private readonly uint MaskSeed = 1234;
private readonly double MaskPersistence = 0.5;
private readonly double MaskLacunarity = Math.PI * 2 / 3;
private readonly double MaskFrequency = 1;
private readonly uint MaskOctaves = 3;
private readonly double MaskThreshold;
private readonly int PointSize = 1;
private readonly double MaskPower = 1;
public LayerPoints(TomlTable table)
{
if (table.TryGetValue("seed", out var tomlObject))
{
Seed = tomlObject.Get<int>();
}
if (table.TryGetValue("count", out tomlObject))
{
PointCount = tomlObject.Get<int>();
}
if (table.TryGetValue("sourcefactor", out tomlObject))
{
SrcFactor = (BlendFactor) Enum.Parse(typeof(BlendFactor), tomlObject.Get<string>());
}
if (table.TryGetValue("destfactor", out tomlObject))
{
DstFactor = (BlendFactor) Enum.Parse(typeof(BlendFactor), tomlObject.Get<string>());
}
if (table.TryGetValue("farcolor", out tomlObject))
{
FarColor = Color.FromHex(tomlObject.Get<string>());
}
if (table.TryGetValue("closecolor", out tomlObject))
{
CloseColor = Color.FromHex(tomlObject.Get<string>());
}
if (table.TryGetValue("pointsize", out tomlObject))
{
PointSize = tomlObject.Get<int>();
}
// Noise mask stuff.
if (table.TryGetValue("mask", out tomlObject))
{
Masked = tomlObject.Get<bool>();
}
if (table.TryGetValue("maskseed", out tomlObject))
{
MaskSeed = (uint) tomlObject.Get<int>();
}
if (table.TryGetValue("maskpersistence", out tomlObject))
{
MaskPersistence = double.Parse(tomlObject.Get<string>(), CultureInfo.InvariantCulture);
}
if (table.TryGetValue("masklacunarity", out tomlObject))
{
MaskLacunarity = double.Parse(tomlObject.Get<string>(), CultureInfo.InvariantCulture);
}
if (table.TryGetValue("maskfrequency", out tomlObject))
{
MaskFrequency = double.Parse(tomlObject.Get<string>(), CultureInfo.InvariantCulture);
}
if (table.TryGetValue("maskoctaves", out tomlObject))
{
MaskOctaves = (uint) tomlObject.Get<int>();
}
if (table.TryGetValue("maskthreshold", out tomlObject))
{
MaskThreshold = double.Parse(tomlObject.Get<string>(), CultureInfo.InvariantCulture);
}
if (table.TryGetValue("masknoise_type", out tomlObject))
{
switch (tomlObject.Get<string>())
{
case "fbm":
MaskNoiseType = NoiseGenerator.NoiseType.Fbm;
break;
case "ridged":
MaskNoiseType = NoiseGenerator.NoiseType.Ridged;
break;
default:
throw new InvalidOperationException();
}
}
if (table.TryGetValue("maskpower", out tomlObject))
{
MaskPower = double.Parse(tomlObject.Get<string>(), CultureInfo.InvariantCulture);
}
}
public override void Apply(Image<Rgba32> bitmap)
{
// Temporary buffer so we don't mess up blending.
var buffer = new Image<Rgba32>(Configuration.Default, bitmap.Width, bitmap.Height, Rgba32.Black);
if (Masked)
{
GenPointsMasked(buffer);
}
else
{
GenPoints(buffer);
}
for (var x = 0; x < bitmap.Width; x++)
{
for (var y = 0; y < bitmap.Height; y++)
{
var dstColor = bitmap[x, y].ConvertImgSharp();
var srcColor = buffer[x, y].ConvertImgSharp();
bitmap[x, y] = Color.Blend(dstColor, srcColor, DstFactor, SrcFactor).ConvertImgSharp();
}
}
}
private void GenPoints(Image<Rgba32> buffer)
{
var o = PointSize - 1;
var random = new Random(Seed);
for (var i = 0; i < PointCount; i++)
{
var relX = random.NextDouble();
var relY = random.NextDouble();
var x = (int) (relX * buffer.Width);
var y = (int) (relY * buffer.Height);
var dist = random.NextDouble();
for (var ox = x - o; ox <= x + o; ox++)
{
for (var oy = y - o; oy <= y + o; oy++)
{
var color = Color.InterpolateBetween(FarColor, CloseColor, (float) dist).ConvertImgSharp();
buffer[MathHelper.Mod(ox, buffer.Width), MathHelper.Mod(oy, buffer.Width)] = color;
}
}
}
}
void GenPointsMasked(Image<Rgba32> buffer)
{
var o = PointSize - 1;
var random = new Random(Seed);
var noise = new NoiseGenerator(MaskNoiseType);
noise.SetSeed(MaskSeed);
noise.SetFrequency(MaskFrequency);
noise.SetPersistence(MaskPersistence);
noise.SetLacunarity(MaskLacunarity);
noise.SetOctaves(MaskOctaves);
noise.SetPeriodX(buffer.Width);
noise.SetPeriodY(buffer.Height);
var threshVal = 1 / (1 - MaskThreshold);
var powFactor = 1 / MaskPower;
const int maxPointAttemptCount = 9999;
var pointAttemptCount = 0;
for (var i = 0; i < PointCount; i++)
{
var relX = random.NextDouble();
var relY = random.NextDouble();
var x = (int) (relX * buffer.Width);
var y = (int) (relY * buffer.Height);
// Grab noise at this point.
var noiseVal = Math.Min(1, Math.Max(0, (noise.GetNoiseTiled(x, y) + 1) / 2));
// Threshold
noiseVal = Math.Max(0, noiseVal - MaskThreshold);
noiseVal *= threshVal;
noiseVal = Math.Pow(noiseVal, powFactor);
var randomThresh = random.NextDouble();
if (randomThresh > noiseVal)
{
if (++pointAttemptCount <= maxPointAttemptCount)
{
i--;
}
continue;
}
var dist = random.NextDouble();
for (var ox = x - o; ox <= x + o; ox++)
{
for (var oy = y - o; oy <= y + o; oy++)
{
var color = Color.InterpolateBetween(FarColor, CloseColor, (float) dist).ConvertImgSharp();
buffer[MathHelper.Mod(ox, buffer.Width), MathHelper.Mod(oy, buffer.Height)] = color;
}
}
}
}
}
}
}

View File

@@ -1,113 +0,0 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Content.Client.Interfaces.Parallax;
using Nett;
using SixLabors.ImageSharp;
using SixLabors.Primitives;
using Robust.Client.Graphics;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.Log;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Utility;
namespace Content.Client.Parallax
{
internal sealed class ParallaxManager : IParallaxManager, IPostInjectInit
{
#pragma warning disable 649
[Dependency] private readonly IResourceCache _resourceCache;
[Dependency] private readonly ILogManager _logManager;
[Dependency] private readonly IConfigurationManager _configurationManager;
#pragma warning restore 649
private static readonly ResourcePath ParallaxConfigPath = new ResourcePath("/parallax_config.toml");
// Both of these below are in the user directory.
private static readonly ResourcePath ParallaxPath = new ResourcePath("/parallax_cache.png");
private static readonly ResourcePath ParallaxConfigOld = new ResourcePath("/parallax_config_old");
public event Action<Texture> OnTextureLoaded;
public Texture ParallaxTexture { get; private set; }
public async void LoadParallax()
{
if (!_configurationManager.GetCVar<bool>("parallax.enabled"))
{
return;
}
MemoryStream configStream = null;
string contents;
TomlTable table;
try
{
// Load normal config into memory
if (!_resourceCache.TryContentFileRead(ParallaxConfigPath, out configStream))
{
Logger.ErrorS("parallax", "Parallax config not found.");
return;
}
using (var reader = new StreamReader(configStream, EncodingHelpers.UTF8))
{
contents = reader.ReadToEnd();
}
if (_resourceCache.UserData.Exists(ParallaxConfigOld))
{
bool match;
using (var data = _resourceCache.UserData.Open(ParallaxConfigOld, FileMode.Open))
using (var reader = new StreamReader(data, EncodingHelpers.UTF8))
{
match = reader.ReadToEnd() == contents;
}
if (match)
{
using (var stream = _resourceCache.UserData.Open(ParallaxPath, FileMode.Open))
{
ParallaxTexture = Texture.LoadFromPNGStream(stream, "Parallax");
}
OnTextureLoaded?.Invoke(ParallaxTexture);
return;
}
}
table = Toml.ReadString(contents);
}
finally
{
configStream?.Dispose();
}
var sawmill = _logManager.GetSawmill("parallax");
// Generate the parallax in the thread pool.
var image = await Task.Run(() => ParallaxGenerator.GenerateParallax(table, new Size(1920, 1080), sawmill));
// And load it in the main thread for safety reasons.
ParallaxTexture = Texture.LoadFromImage(image, "Parallax");
// Store it and CRC so further game starts don't need to regenerate it.
using (var stream = _resourceCache.UserData.Open(ParallaxPath, FileMode.Create))
{
image.SaveAsPng(stream);
}
using (var stream = _resourceCache.UserData.Open(ParallaxConfigOld, FileMode.Create))
using (var writer = new StreamWriter(stream, EncodingHelpers.UTF8))
{
writer.Write(contents);
}
OnTextureLoaded?.Invoke(ParallaxTexture);
}
public void PostInject()
{
_configurationManager.RegisterCVar("parallax.enabled", true);
}
}
}

View File

@@ -1,67 +0,0 @@
using Content.Client.Interfaces.Parallax;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Graphics.Shaders;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.Parallax
{
public class ParallaxOverlay : Overlay
{
#pragma warning disable 649
[Dependency] private readonly IParallaxManager _parallaxManager;
[Dependency] private readonly IEyeManager _eyeManager;
[Dependency] private readonly IPrototypeManager _prototypeManager;
[Dependency] private readonly IMapManager _mapManager;
#pragma warning restore 649
public override bool AlwaysDirty => true;
private const float Slowness = 0.5f;
private Texture _parallaxTexture;
public override OverlaySpace Space => OverlaySpace.ScreenSpaceBelowWorld;
public ParallaxOverlay() : base(nameof(ParallaxOverlay))
{
IoCManager.InjectDependencies(this);
Shader = _prototypeManager.Index<ShaderPrototype>("unshaded").Instance();
if (_parallaxManager.ParallaxTexture == null)
{
_parallaxManager.OnTextureLoaded += texture => _parallaxTexture = texture;
}
else
{
_parallaxTexture = _parallaxManager.ParallaxTexture;
}
}
protected override void Draw(DrawingHandleBase handle)
{
if (_parallaxTexture == null)
{
return;
}
var screenHandle = (DrawingHandleScreen) handle;
var (sizeX, sizeY) = _parallaxTexture.Size;
var (posX, posY) = _eyeManager.ScreenToWorld(Vector2.Zero).ToWorld(_mapManager).Position;
var (ox, oy) = (Vector2i) new Vector2(-posX / Slowness, posY / Slowness);
ox = MathHelper.Mod(ox, sizeX);
oy = MathHelper.Mod(oy, sizeY);
screenHandle.DrawTexture(_parallaxTexture, new Vector2(ox, oy));
screenHandle.DrawTexture(_parallaxTexture, new Vector2(ox - sizeX, oy));
screenHandle.DrawTexture(_parallaxTexture, new Vector2(ox, oy - sizeY));
screenHandle.DrawTexture(_parallaxTexture, new Vector2(ox - sizeX, oy - sizeY));
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Content.Client")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Content.Client")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a2e5f175-78af-4ddd-8f97-e2d2552372ed")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,251 +0,0 @@
using System.Collections.Generic;
using Content.Client.GameObjects.Components.Research;
using Content.Shared.Materials;
using Content.Shared.Research;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.Utility;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Timers;
using Robust.Shared.Utility;
namespace Content.Client.Research
{
public class LatheMenu : SS14Window
{
#pragma warning disable CS0649
[Dependency]
private IPrototypeManager PrototypeManager;
#pragma warning restore
private ItemList Items;
private ItemList Materials;
private LineEdit AmountLineEdit;
private LineEdit SearchBar;
public Button QueueButton;
protected override Vector2? CustomSize => (300, 450);
public LatheBoundUserInterface Owner { get; set; }
private List<LatheRecipePrototype> _recipes = new List<LatheRecipePrototype>();
private List<LatheRecipePrototype> _shownRecipes = new List<LatheRecipePrototype>();
public LatheMenu()
{
}
public LatheMenu(string name) : base(name)
{
}
protected override void Initialize()
{
base.Initialize();
IoCManager.InjectDependencies(this);
Title = "Lathe Menu";
var margin = new MarginContainer()
{
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsHorizontal = SizeFlags.FillExpand,
MarginTop = 5f,
MarginLeft = 5f,
MarginRight = -5f,
MarginBottom = -5f,
};
margin.SetAnchorAndMarginPreset(LayoutPreset.Wide);
var vbox = new VBoxContainer()
{
SizeFlagsVertical = SizeFlags.FillExpand,
SeparationOverride = 5,
};
vbox.SetAnchorAndMarginPreset(LayoutPreset.Wide);
var hboxButtons = new HBoxContainer()
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 1,
};
QueueButton = new Button()
{
Text = "Queue",
TextAlign = Button.AlignMode.Center,
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 1,
};
var spacer = new Control()
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 3,
};
spacer.SetAnchorAndMarginPreset(LayoutPreset.Wide);
var hboxFilter = new HBoxContainer()
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 1
};
SearchBar = new LineEdit()
{
PlaceHolder = "Search Designs",
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 3
};
SearchBar.OnTextChanged += Populate;
var filterButton = new Button()
{
Text = "Filter",
TextAlign = Button.AlignMode.Center,
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 1,
Disabled = true,
};
Items = new ItemList()
{
SizeFlagsStretchRatio = 8,
SizeFlagsVertical = SizeFlags.FillExpand,
};
Items.OnItemSelected += ItemSelected;
AmountLineEdit = new LineEdit()
{
PlaceHolder = "Amount",
Text = "1",
SizeFlagsHorizontal = SizeFlags.FillExpand,
};
AmountLineEdit.OnTextChanged += PopulateDisabled;
Materials = new ItemList()
{
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 3
};
hboxButtons.AddChild(spacer);
hboxButtons.AddChild(QueueButton);
hboxFilter.AddChild(SearchBar);
hboxFilter.AddChild(filterButton);
vbox.AddChild(hboxButtons);
vbox.AddChild(hboxFilter);
vbox.AddChild(Items);
vbox.AddChild(AmountLineEdit);
vbox.AddChild(Materials);
margin.AddChild(vbox);
Contents.AddChild(margin);
}
public void ItemSelected(ItemList.ItemListSelectedEventArgs args)
{
int.TryParse(AmountLineEdit.Text, out var quantity);
if (quantity <= 0) quantity = 1;
Owner.Queue(_shownRecipes[args.ItemIndex], quantity);
Items.SelectMode = ItemList.ItemListSelectMode.None;
Timer.Spawn(100, () =>
{
Items.Unselect(args.ItemIndex);
Items.SelectMode = ItemList.ItemListSelectMode.Single;
});
}
public void PopulateMaterials()
{
Materials.Clear();
foreach (var (id, amount) in Owner.Storage)
{
if (!PrototypeManager.TryIndex(id, out MaterialPrototype materialPrototype)) continue;
var material = materialPrototype.Material;
Materials.AddItem($"{material.Name} {amount} cm³", material.Icon.Frame0(), false);
}
}
/// <summary>
/// Disables or enables shown recipes depending on whether there are enough materials for it or not.
/// </summary>
public void PopulateDisabled()
{
int.TryParse(AmountLineEdit.Text, out var quantity);
if (quantity <= 0) quantity = 1;
for (var i = 0; i < _shownRecipes.Count; i++)
{
var prototype = _shownRecipes[i];
Items.SetItemDisabled(i, !Owner.Lathe.CanProduce(prototype, quantity));
}
}
/// <inheritdoc cref="PopulateDisabled()"/>
public void PopulateDisabled(LineEdit.LineEditEventArgs args)
{
PopulateDisabled();
}
/// <summary>
/// Adds shown recipes to the ItemList control.
/// </summary>
public void PopulateList()
{
Items.Clear();
for (var i = 0; i < _shownRecipes.Count; i++)
{
var prototype = _shownRecipes[i];
Items.AddItem(prototype.Name, prototype.Icon.Frame0());
}
PopulateDisabled();
}
/// <summary>
/// Populates the list of recipes that will actually be shown, using the current filters.
/// </summary>
public void Populate()
{
_shownRecipes.Clear();
foreach (var prototype in Owner.Database)
{
if (SearchBar.Text.Trim().Length != 0)
{
if (prototype.Name.ToLowerInvariant().Contains(SearchBar.Text.Trim().ToLowerInvariant()))
_shownRecipes.Add(prototype);
continue;
}
_shownRecipes.Add(prototype);
}
PopulateList();
}
/// <inheritdoc cref="Populate"/>
public void Populate(LineEdit.LineEditEventArgs args)
{
Populate();
}
}
}

View File

@@ -1,142 +0,0 @@
using Content.Client.GameObjects.Components.Research;
using Content.Shared.Research;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.Utility;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.ViewVariables;
namespace Content.Client.Research
{
public class LatheQueueMenu : SS14Window
{
protected override Vector2? CustomSize => (300, 450);
public LatheBoundUserInterface Owner { get; set; }
[ViewVariables]
private ItemList QueueList;
private Label NameLabel;
private Label Description;
private TextureRect Icon;
protected override void Initialize()
{
base.Initialize();
Title = "Lathe Queue";
var margin = new MarginContainer()
{
MarginTop = 5f,
MarginLeft = 5f,
MarginRight = -5f,
MarginBottom = -5f,
};
margin.SetAnchorAndMarginPreset(LayoutPreset.Wide);
var vbox = new VBoxContainer();
vbox.SetAnchorAndMarginPreset(LayoutPreset.Wide);
var descMargin = new MarginContainer()
{
MarginTop = 5f,
MarginLeft = 5f,
MarginRight = -5f,
MarginBottom = -5f,
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 2,
};
var hbox = new HBoxContainer()
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
};
Icon = new TextureRect()
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 2,
};
var vboxInfo = new VBoxContainer()
{
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 3,
};
NameLabel = new Label()
{
RectClipContent = true,
SizeFlagsHorizontal = SizeFlags.Fill,
};
Description = new Label()
{
RectClipContent = true,
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsHorizontal = SizeFlags.Fill,
};
QueueList = new ItemList()
{
SizeFlagsHorizontal = SizeFlags.Fill,
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 3,
SelectMode = ItemList.ItemListSelectMode.None
};
vboxInfo.AddChild(NameLabel);
vboxInfo.AddChild(Description);
hbox.AddChild(Icon);
hbox.AddChild(vboxInfo);
descMargin.AddChild(hbox);
vbox.AddChild(descMargin);
vbox.AddChild(QueueList);
margin.AddChild(vbox);
Contents.AddChild(margin);
ClearInfo();
}
public void SetInfo(LatheRecipePrototype recipe)
{
Icon.Texture = recipe.Icon.Frame0();
if (recipe.Name != null)
NameLabel.Text = recipe.Name;
if (recipe.Description != null)
Description.Text = recipe.Description;
}
public void ClearInfo()
{
Icon.Texture = Texture.Transparent;
NameLabel.Text = "-------";
Description.Text = "Not producing anything.";
}
public void PopulateList()
{
QueueList.Clear();
var idx = 1;
foreach (var recipe in Owner.QueuedRecipes)
{
QueueList.AddItem($"{idx}. {recipe.Name}", recipe.Icon.Frame0(), false);
idx++;
}
}
}
}

View File

@@ -1,114 +0,0 @@
using Robust.Client.Console;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Placement;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface
{
internal sealed class EscapeMenu : SS14Window
{
private readonly IClientConsole _console;
private readonly ITileDefinitionManager __tileDefinitionManager;
private readonly IPlacementManager _placementManager;
private readonly IPrototypeManager _prototypeManager;
private readonly IResourceCache _resourceCache;
private readonly IConfigurationManager _configSystem;
private readonly ILocalizationManager _localizationManager;
private BaseButton QuitButton;
private BaseButton OptionsButton;
private BaseButton SpawnEntitiesButton;
private BaseButton SpawnTilesButton;
private OptionsMenu optionsMenu;
public EscapeMenu(IClientConsole console,
ITileDefinitionManager tileDefinitionManager,
IPlacementManager placementManager,
IPrototypeManager prototypeManager,
IResourceCache resourceCache,
IConfigurationManager configSystem, ILocalizationManager localizationManager)
{
_configSystem = configSystem;
_localizationManager = localizationManager;
_console = console;
__tileDefinitionManager = tileDefinitionManager;
_placementManager = placementManager;
_prototypeManager = prototypeManager;
_resourceCache = resourceCache;
PerformLayout();
}
private void PerformLayout()
{
optionsMenu = new OptionsMenu(_configSystem);
Resizable = false;
Title = "Menu";
var vBox = new VBoxContainer {SeparationOverride = 2};
Contents.AddChild(vBox);
SpawnEntitiesButton = new Button {Text = "Spawn Entities"};
SpawnEntitiesButton.OnPressed += OnSpawnEntitiesButtonClicked;
vBox.AddChild(SpawnEntitiesButton);
SpawnTilesButton = new Button {Text = "Spawn Tiles"};
SpawnTilesButton.OnPressed += OnSpawnTilesButtonClicked;
vBox.AddChild(SpawnTilesButton);
// Add a spacer.
vBox.AddChild(new Control { CustomMinimumSize = (0, 5)});
OptionsButton = new Button {Text = "Options"};
OptionsButton.OnPressed += OnOptionsButtonClicked;
vBox.AddChild(OptionsButton);
QuitButton = new Button {Text = "Quit"};
QuitButton.OnPressed += OnQuitButtonClicked;
vBox.AddChild(QuitButton);
Size = CombinedMinimumSize;
}
private void OnQuitButtonClicked(BaseButton.ButtonEventArgs args)
{
_console.ProcessCommand("disconnect");
Dispose();
}
private void OnOptionsButtonClicked(BaseButton.ButtonEventArgs args)
{
optionsMenu.OpenCentered();
}
private void OnSpawnEntitiesButtonClicked(BaseButton.ButtonEventArgs args)
{
var window = new EntitySpawnWindow(_placementManager, _prototypeManager, _resourceCache, _localizationManager);
window.OpenToLeft();
}
private void OnSpawnTilesButtonClicked(BaseButton.ButtonEventArgs args)
{
var window = new TileSpawnWindow(__tileDefinitionManager, _placementManager, _resourceCache);
window.OpenToLeft();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
optionsMenu.Dispose();
}
}
}
}

View File

@@ -1,391 +0,0 @@
using System;
using Content.Client.Utility;
using Content.Shared.Input;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
/// <summary>
/// Responsible for laying out the default game HUD.
/// </summary>
public interface IGameHud
{
Control RootControl { get; }
// Escape top button.
bool EscapeButtonDown { get; set; }
Action<bool> EscapeButtonToggled { get; set; }
// Character top button.
bool CharacterButtonDown { get; set; }
bool CharacterButtonVisible { get; set; }
Action<bool> CharacterButtonToggled { get; set; }
// Inventory top button.
bool InventoryButtonDown { get; set; }
bool InventoryButtonVisible { get; set; }
Action<bool> InventoryButtonToggled { get; set; }
// Crafting top button.
bool CraftingButtonDown { get; set; }
bool CraftingButtonVisible { get; set; }
Action<bool> CraftingButtonToggled { get; set; }
// Sandbox top button.
bool SandboxButtonDown { get; set; }
bool SandboxButtonVisible { get; set; }
Action<bool> SandboxButtonToggled { get; set; }
Control HandsContainer { get; }
Control InventoryQuickButtonContainer { get; }
// Init logic.
void Initialize();
}
internal sealed class GameHud : IGameHud
{
private HBoxContainer _topButtonsContainer;
private TopButton _buttonEscapeMenu;
private TopButton _buttonTutorial;
private TopButton _buttonCharacterMenu;
private TopButton _buttonInventoryMenu;
private TopButton _buttonCraftingMenu;
private TopButton _buttonSandboxMenu;
private TutorialWindow _tutorialWindow;
#pragma warning disable 649
[Dependency] private readonly IResourceCache _resourceCache;
[Dependency] private readonly ILocalizationManager _loc;
[Dependency] private readonly IInputManager _inputManager;
#pragma warning restore 649
public Control HandsContainer { get; private set; }
public Control InventoryQuickButtonContainer { get; private set; }
public void Initialize()
{
RootControl = new Control {MouseFilter = Control.MouseFilterMode.Ignore};
RootControl.SetAnchorPreset(Control.LayoutPreset.Wide);
var escapeTexture = _resourceCache.GetTexture("/Textures/UserInterface/hamburger.svg.96dpi.png");
var characterTexture = _resourceCache.GetTexture("/Textures/UserInterface/character.svg.96dpi.png");
var inventoryTexture = _resourceCache.GetTexture("/Textures/UserInterface/inventory.svg.96dpi.png");
var craftingTexture = _resourceCache.GetTexture("/Textures/UserInterface/hammer.svg.96dpi.png");
var tutorialTexture = _resourceCache.GetTexture("/Textures/UserInterface/students-cap.svg.96dpi.png");
var sandboxTexture = _resourceCache.GetTexture("/Textures/UserInterface/sandbox.svg.96dpi.png");
_topButtonsContainer = new HBoxContainer
{
SeparationOverride = 4
};
RootControl.AddChild(_topButtonsContainer);
_topButtonsContainer.SetAnchorAndMarginPreset(Control.LayoutPreset.TopLeft, margin: 10);
// TODO: Pull key names here from the actual key binding config.
// Escape
_buttonEscapeMenu = new TopButton(escapeTexture, "Esc")
{
ToolTip = _loc.GetString("Open escape menu.")
};
_topButtonsContainer.AddChild(_buttonEscapeMenu);
_buttonEscapeMenu.OnToggled += args => EscapeButtonToggled?.Invoke(args.Pressed);
// Tutorial
_buttonTutorial = new TopButton(tutorialTexture, "F1")
{
ToolTip = _loc.GetString("Open tutorial.")
};
_topButtonsContainer.AddChild(_buttonTutorial);
_buttonTutorial.OnToggled += a => ButtonTutorialOnOnToggled();
// Character
_buttonCharacterMenu = new TopButton(characterTexture, "C")
{
ToolTip = _loc.GetString("Open character menu."),
Visible = false
};
_topButtonsContainer.AddChild(_buttonCharacterMenu);
_buttonCharacterMenu.OnToggled += args => CharacterButtonToggled?.Invoke(args.Pressed);
// Inventory
_buttonInventoryMenu = new TopButton(inventoryTexture, "I")
{
ToolTip = _loc.GetString("Open inventory menu."),
Visible = false
};
_topButtonsContainer.AddChild(_buttonInventoryMenu);
_buttonInventoryMenu.OnToggled += args => InventoryButtonToggled?.Invoke(args.Pressed);
// Crafting
_buttonCraftingMenu = new TopButton(craftingTexture, "G")
{
ToolTip = _loc.GetString("Open crafting menu."),
Visible = false
};
_topButtonsContainer.AddChild(_buttonCraftingMenu);
_buttonCraftingMenu.OnToggled += args => CraftingButtonToggled?.Invoke(args.Pressed);
// Sandbox
_buttonSandboxMenu = new TopButton(sandboxTexture, "B")
{
ToolTip = _loc.GetString("Open sandbox menu."),
Visible = true
};
_topButtonsContainer.AddChild(_buttonSandboxMenu);
_buttonSandboxMenu.OnToggled += args => SandboxButtonToggled?.Invoke(args.Pressed);
_tutorialWindow = new TutorialWindow();
_tutorialWindow.OnClose += () => _buttonTutorial.Pressed = false;
_inputManager.SetInputCommand(ContentKeyFunctions.OpenTutorial,
InputCmdHandler.FromDelegate(s => ButtonTutorialOnOnToggled()));
var inventoryContainer = new HBoxContainer
{
GrowHorizontal = Control.GrowDirection.Begin,
GrowVertical = Control.GrowDirection.Begin,
SeparationOverride = 10
};
RootControl.AddChild(inventoryContainer);
inventoryContainer.SetAnchorAndMarginPreset(Control.LayoutPreset.BottomRight);
InventoryQuickButtonContainer = new MarginContainer
{
GrowHorizontal = Control.GrowDirection.Begin,
GrowVertical = Control.GrowDirection.Begin,
};
HandsContainer = new MarginContainer
{
GrowHorizontal = Control.GrowDirection.Both,
GrowVertical = Control.GrowDirection.Begin
};
inventoryContainer.Children.Add(HandsContainer);
inventoryContainer.Children.Add(InventoryQuickButtonContainer);
}
private void ButtonTutorialOnOnToggled()
{
if (_tutorialWindow.IsOpen)
{
if (!_tutorialWindow.IsAtFront())
{
_tutorialWindow.MoveToFront();
_buttonTutorial.Pressed = true;
}
else
{
_tutorialWindow.Close();
_buttonTutorial.Pressed = false;
}
}
else
{
_tutorialWindow.OpenCentered();
_buttonTutorial.Pressed = true;
}
}
public Control RootControl { get; private set; }
public bool EscapeButtonDown
{
get => _buttonEscapeMenu.Pressed;
set => _buttonEscapeMenu.Pressed = value;
}
public Action<bool> EscapeButtonToggled { get; set; }
public bool CharacterButtonDown
{
get => _buttonCharacterMenu.Pressed;
set => _buttonCharacterMenu.Pressed = value;
}
public bool CharacterButtonVisible
{
get => _buttonCharacterMenu.Visible;
set => _buttonCharacterMenu.Visible = value;
}
public Action<bool> CharacterButtonToggled { get; set; }
public bool InventoryButtonDown
{
get => _buttonInventoryMenu.Pressed;
set => _buttonInventoryMenu.Pressed = value;
}
public bool InventoryButtonVisible
{
get => _buttonInventoryMenu.Visible;
set => _buttonInventoryMenu.Visible = value;
}
public Action<bool> InventoryButtonToggled { get; set; }
public bool CraftingButtonDown
{
get => _buttonCraftingMenu.Pressed;
set => _buttonCraftingMenu.Pressed = value;
}
public bool CraftingButtonVisible
{
get => _buttonCraftingMenu.Visible;
set => _buttonCraftingMenu.Visible = value;
}
public Action<bool> CraftingButtonToggled { get; set; }
public bool SandboxButtonDown
{
get => _buttonSandboxMenu.Pressed;
set => _buttonSandboxMenu.Pressed = value;
}
public bool SandboxButtonVisible
{
get => _buttonSandboxMenu.Visible;
set => _buttonSandboxMenu.Visible = value;
}
public Action<bool> SandboxButtonToggled { get; set; }
public sealed class TopButton : BaseButton
{
public const string StyleClassLabelTopButton = "topButtonLabel";
private static readonly Color ColorNormal = Color.FromHex("#7b7e9e");
private static readonly Color ColorHovered = Color.FromHex("#9699bb");
private static readonly Color ColorPressed = Color.FromHex("#789B8C");
private readonly VBoxContainer _container;
private readonly TextureRect _textureRect;
private readonly Label _label;
public TopButton(Texture texture, string keyName)
{
ToggleMode = true;
_container = new VBoxContainer {MouseFilter = MouseFilterMode.Ignore};
AddChild(_container);
_container.AddChild(_textureRect = new TextureRect
{
Texture = texture,
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
SizeFlagsVertical = SizeFlags.Expand | SizeFlags.ShrinkCenter,
MouseFilter = MouseFilterMode.Ignore,
ModulateSelfOverride = ColorNormal,
CustomMinimumSize = (0, 32),
Stretch = TextureRect.StretchMode.KeepCentered
});
_container.AddChild(_label = new Label
{
Text = keyName,
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
MouseFilter = MouseFilterMode.Ignore,
ModulateSelfOverride = ColorNormal
});
_label.AddStyleClass(StyleClassLabelTopButton);
_container.SetAnchorAndMarginPreset(LayoutPreset.Wide);
DrawModeChanged();
}
protected override Vector2 CalculateMinimumSize()
{
var styleSize = ActualStyleBox?.MinimumSize ?? Vector2.Zero;
return (0, 4) + styleSize + _container?.CombinedMinimumSize ?? Vector2.Zero;
}
protected override void Draw(DrawingHandleScreen handle)
{
ActualStyleBox?.Draw(handle, PixelSizeBox);
}
private StyleBox ActualStyleBox
{
get
{
TryGetStyleProperty(Button.StylePropertyStyleBox, out StyleBox ret);
return ret;
}
}
protected override void DrawModeChanged()
{
switch (DrawMode)
{
case DrawModeEnum.Normal:
StylePseudoClass = Button.StylePseudoClassNormal;
_textureRect.ModulateSelfOverride = ColorNormal;
_label.ModulateSelfOverride = ColorNormal;
break;
case DrawModeEnum.Pressed:
StylePseudoClass = Button.StylePseudoClassPressed;
_textureRect.ModulateSelfOverride = ColorPressed;
_label.ModulateSelfOverride = ColorPressed;
break;
case DrawModeEnum.Hover:
StylePseudoClass = Button.StylePseudoClassHover;
_textureRect.ModulateSelfOverride = ColorHovered;
_label.ModulateSelfOverride = ColorHovered;
break;
case DrawModeEnum.Disabled:
break;
}
}
protected override void StylePropertiesChanged()
{
base.StylePropertiesChanged();
if (_container == null)
{
return;
}
var box = ActualStyleBox ?? new StyleBoxEmpty();
_container.MarginLeft = box.GetContentMargin(StyleBox.Margin.Left);
_container.MarginRight = -box.GetContentMargin(StyleBox.Margin.Right);
_container.MarginTop = box.GetContentMargin(StyleBox.Margin.Top) + 4;
_container.MarginBottom = -box.GetContentMargin(StyleBox.Margin.Bottom);
}
}
}
}

View File

@@ -1,109 +1,95 @@
using Content.Client.GameObjects;
using Content.Client.GameObjects.EntitySystems;
using Content.Client.Interfaces.GameObjects;
using Content.Client.Utility;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using SS14.Client.GameObjects;
using SS14.Client.Graphics;
using SS14.Client.Graphics.Drawing;
using SS14.Client.Input;
using SS14.Client.Interfaces.Player;
using SS14.Client.Interfaces.ResourceManagement;
using SS14.Client.Interfaces.UserInterface;
using SS14.Client.ResourceManagement;
using SS14.Client.UserInterface;
using SS14.Client.UserInterface.Controls;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.IoC;
using SS14.Shared.Log;
using SS14.Shared.Maths;
namespace Content.Client.UserInterface
{
public class HandsGui : Control
{
private const int BoxSpacing = 0;
private const int BoxSize = 64;
private static readonly Color _inactiveColor = new Color(90, 90, 90);
private const int BOX_SPACING = 1;
// The boxes are square so that's both width and height.
private const int BOX_SIZE = 50;
#pragma warning disable 0649
[Dependency] private readonly IPlayerManager _playerManager;
[Dependency] private readonly IResourceCache _resourceCache;
[Dependency] private readonly ILocalizationManager _loc;
#pragma warning restore 0649
private readonly IPlayerManager _playerManager = IoCManager.Resolve<IPlayerManager>();
private readonly IUserInterfaceManager _userInterfaceManager = IoCManager.Resolve<IUserInterfaceManager>();
private StyleBoxTexture handBox;
private StyleBoxTexture inactiveHandBox;
private Texture TextureHandLeft;
private Texture TextureHandRight;
private Texture TextureHandActive;
private IEntity LeftHand;
private IEntity RightHand;
private UIBox2i _handL;
private UIBox2i _handR;
private SpriteView LeftSpriteView;
private SpriteView RightSpriteView;
private TextureRect ActiveHandRect;
private UiHandInfo LeftHand;
private UiHandInfo RightHand;
private Box2i handL;
private Box2i handR;
protected override void Initialize()
{
base.Initialize();
IoCManager.InjectDependencies(this);
ToolTip = _loc.GetString("Your hands");
_handR = new UIBox2i(0, 0, BoxSize, BoxSize);
_handL = _handR.Translated((BoxSize + BoxSpacing, 0));
var _resMgr = IoCManager.Resolve<IResourceCache>();
var handsBoxTexture = _resMgr.GetResource<TextureResource>("/Textures/UserInterface/handsbox.png");
handBox = new StyleBoxTexture()
{
Texture = handsBoxTexture,
};
handBox.SetMargin(StyleBox.Margin.All, 6);
inactiveHandBox = new StyleBoxTexture(handBox)
{
Modulate = _inactiveColor,
};
SetMarginsPreset(LayoutPreset.CenterBottom);
SetAnchorPreset(LayoutPreset.CenterBottom);
handL = new Box2i(0, 0, BOX_SIZE, BOX_SIZE);
handR = handL.Translated(new Vector2i(BOX_SIZE + BOX_SPACING, 0));
SS14.Shared.Log.Logger.Debug($"{handL}, {handR}");
MouseFilter = MouseFilterMode.Stop;
TextureHandLeft = _resourceCache.GetTexture("/Textures/UserInterface/Inventory/hand_l.png");
TextureHandRight = _resourceCache.GetTexture("/Textures/UserInterface/Inventory/hand_r.png");
TextureHandActive = _resourceCache.GetTexture("/Textures/UserInterface/Inventory/hand_active.png");
AddChild(new TextureRect
{
Texture = TextureHandLeft,
Size = _handL.Size,
Position = _handL.TopLeft,
TextureScale = (2, 2)
});
AddChild(new TextureRect
{
Texture = TextureHandRight,
Size = _handR.Size,
Position = _handR.TopLeft,
TextureScale = (2, 2)
});
AddChild(ActiveHandRect = new TextureRect
{
Texture = TextureHandActive,
Size = _handL.Size,
Position = _handL.TopLeft,
TextureScale = (2, 2)
});
LeftSpriteView = new SpriteView
{
MouseFilter = MouseFilterMode.Ignore,
Scale = (2, 2)
};
AddChild(LeftSpriteView);
LeftSpriteView.Size = _handL.Size;
LeftSpriteView.Position = _handL.TopLeft;
RightSpriteView = new SpriteView
{
MouseFilter = MouseFilterMode.Ignore,
Scale = (2, 2)
};
AddChild(RightSpriteView);
RightSpriteView.Size = _handR.Size;
RightSpriteView.Position = _handR.TopLeft;
}
protected override Vector2 CalculateMinimumSize()
{
return new Vector2(BoxSize * 2 + BoxSpacing, BoxSize) * UIScale;
return new Vector2(BOX_SIZE * 2 + 1, BOX_SIZE);
}
protected override void Draw(DrawingHandle handle)
{
if (!TryGetHands(out IHandsComponent hands))
return;
var leftActive = hands.ActiveIndex == "left";
handle.DrawStyleBox(handBox, leftActive ? handL : handR);
handle.DrawStyleBox(inactiveHandBox, leftActive ? handR : handL);
if (LeftHand.Entity != null && LeftHand.HeldSprite != null)
{
var bounds = LeftHand.HeldSprite.Size;
handle.DrawTextureRect(LeftHand.HeldSprite,
Box2i.FromDimensions(handL.Left + (int)(handL.Width / 2f - bounds.X / 2f),
handL.Top + (int)(handL.Height / 2f - bounds.Y / 2f),
(int)bounds.X, (int)bounds.Y), tile: false);
}
if (RightHand.Entity != null && RightHand.HeldSprite != null)
{
var bounds = RightHand.HeldSprite.Size;
handle.DrawTextureRect(RightHand.HeldSprite,
Box2i.FromDimensions(handR.Left + (int)(handR.Width / 2f - bounds.Y / 2f),
handR.Top + (int)(handR.Height / 2f - bounds.Y / 2f),
(int)bounds.X, (int)bounds.Y), tile: false);
}
}
/// <summary>
@@ -113,58 +99,57 @@ namespace Content.Client.UserInterface
/// <returns></returns>
private bool TryGetHands(out IHandsComponent hands)
{
hands = default;
hands = null;
if (_playerManager?.LocalPlayer == null)
{
return false;
}
var entity = _playerManager?.LocalPlayer?.ControlledEntity;
return entity != null && entity.TryGetComponent(out hands);
IEntity entity = _playerManager.LocalPlayer.ControlledEntity;
if (entity == null || !entity.TryGetComponent(out hands))
{
return false;
}
return true;
}
public void UpdateHandIcons()
{
if (Parent == null)
{
return;
}
UpdateDraw();
if (!TryGetHands(out var hands))
if (!TryGetHands(out IHandsComponent hands))
return;
var left = hands.GetEntity("left");
var right = hands.GetEntity("right");
ActiveHandRect.Position = hands.ActiveIndex == "left" ? _handL.TopLeft : _handR.TopLeft;
if (left != null)
{
if (left != LeftHand)
if (left != LeftHand.Entity)
{
LeftHand = left;
if (LeftHand.TryGetComponent(out ISpriteComponent sprite))
{
LeftSpriteView.Sprite = sprite;
}
LeftHand.Entity = left;
LeftHand.HeldSprite = GetIconSprite(left);
}
}
else
{
LeftHand = null;
LeftSpriteView.Sprite = null;
LeftHand.Entity = null;
LeftHand.HeldSprite = null;
}
if (right != null)
{
RightHand = right;
if (RightHand.TryGetComponent(out ISpriteComponent sprite))
if (right != RightHand.Entity)
{
RightSpriteView.Sprite = sprite;
RightHand.Entity = right;
RightHand.HeldSprite = GetIconSprite(right);
}
}
else
{
RightHand = null;
RightSpriteView.Sprite = null;
RightHand.Entity = null;
RightHand.HeldSprite = null;
}
}
@@ -182,80 +167,56 @@ namespace Content.Client.UserInterface
return;
//Todo: remove hands interface, so weird
((HandsComponent) hands).UseActiveHand();
}
private void AttackByInHand(string hand)
{
if (!TryGetHands(out var hands))
return;
hands.AttackByInHand(hand);
((HandsComponent)hands).UseActiveHand();
}
protected override bool HasPoint(Vector2 point)
{
return _handL.Contains((Vector2i) point) || _handR.Contains((Vector2i) point);
return handL.Contains((Vector2i)point) || handR.Contains((Vector2i)point);
}
protected override void MouseDown(GUIMouseButtonEventArgs args)
{
base.MouseDown(args);
var leftHandContains = _handL.Contains((Vector2i) args.RelativePosition);
var rightHandContains = _handR.Contains((Vector2i) args.RelativePosition);
string handIndex;
if (leftHandContains)
{
handIndex = "left";
}
else if (rightHandContains)
{
handIndex = "right";
}
else
{
return;
}
var lefthandcontains = handL.Contains((Vector2i)args.RelativePosition);
var righthandcontains = handR.Contains((Vector2i)args.RelativePosition);
if (args.Button == Mouse.Button.Left)
{
if (!TryGetHands(out var hands))
if (!TryGetHands(out IHandsComponent hands))
return;
if (hands.ActiveIndex == handIndex)
{
if ((hands.ActiveIndex == "left" && lefthandcontains)
|| (hands.ActiveIndex == "right" && righthandcontains))
UseActiveHand();
}
else
{
AttackByInHand(handIndex);
}
}
else if (args.Button == Mouse.Button.Middle)
{
SendSwitchHandTo(handIndex);
}
else if (args.Button == Mouse.Button.Right)
{
if (!TryGetHands(out var hands))
if (lefthandcontains)
{
return;
SendSwitchHandTo("left");
}
var entity = hands.GetEntity(handIndex);
if (entity == null)
if (righthandcontains)
{
return;
SendSwitchHandTo("right");
}
var esm = IoCManager.Resolve<IEntitySystemManager>();
esm.GetEntitySystem<VerbSystem>().OpenContextMenu(entity, new ScreenCoordinates(args.GlobalPosition));
}
}
private static Texture GetIconSprite(IEntity entity)
{
if (entity.TryGetComponent<IconComponent>(out var component) && component.Icon != null)
{
return component.Icon.Default;
}
return IoCManager.Resolve<IResourceCache>().GetFallback<TextureResource>();
}
private struct UiHandInfo
{
public IEntity Entity { get; set; }
public Texture HeldSprite { get; set; }
}
}
}

View File

@@ -1,114 +0,0 @@
using Content.Client.Chat;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
internal sealed class LobbyGui : PanelContainer
{
public Label ServerName { get; }
public Label StartTime { get; }
public Button ReadyButton { get; }
public Button ObserveButton { get; }
public Button LeaveButton { get; }
public ChatBox Chat { get; }
public ItemList OnlinePlayerItemList { get; }
public LobbyGui(ILocalizationManager localization, IResourceCache resourceCache)
{
PanelOverride = new StyleBoxFlat {BackgroundColor = new Color(37, 37, 45)};
PanelOverride.SetContentMarginOverride(StyleBox.Margin.All, 4);
var vBox = new VBoxContainer();
AddChild(vBox);
{
// Title bar.
var titleContainer = new HBoxContainer();
vBox.AddChild(titleContainer);
var lobbyTitle = new Label
{
Text = localization.GetString("Lobby"),
SizeFlagsHorizontal = SizeFlags.None
};
lobbyTitle.AddStyleClass(NanoStyle.StyleClassLabelHeading);
titleContainer.AddChild(lobbyTitle);
titleContainer.AddChild(ServerName = new Label
{
SizeFlagsHorizontal = SizeFlags.ShrinkCenter | SizeFlags.Expand
});
ServerName.AddStyleClass(NanoStyle.StyleClassLabelHeading);
titleContainer.AddChild(LeaveButton = new Button
{
SizeFlagsHorizontal = SizeFlags.ShrinkEnd,
Text = localization.GetString("Leave")
});
LeaveButton.AddStyleClass(NanoStyle.StyleClassButtonBig);
}
var hBox = new HBoxContainer {SizeFlagsVertical = SizeFlags.FillExpand};
vBox.AddChild(hBox);
{
var leftVBox = new VBoxContainer {SizeFlagsHorizontal = SizeFlags.FillExpand};
hBox.AddChild(leftVBox);
leftVBox.AddChild(new Placeholder(resourceCache)
{
SizeFlagsVertical = SizeFlags.FillExpand,
PlaceholderText = localization.GetString("Character UI\nPlaceholder")
});
var readyButtons = new HBoxContainer();
leftVBox.AddChild(readyButtons);
readyButtons.AddChild(ObserveButton = new Button
{
Text = localization.GetString("Observe")
});
ObserveButton.AddStyleClass(NanoStyle.StyleClassButtonBig);
readyButtons.AddChild(StartTime = new Label
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
Align = Label.AlignMode.Right
});
readyButtons.AddChild(ReadyButton = new Button
{
ToggleMode = true,
Text = localization.GetString("Ready Up")
});
ReadyButton.AddStyleClass(NanoStyle.StyleClassButtonBig);
leftVBox.AddChild(Chat = new ChatBox {SizeFlagsVertical = SizeFlags.FillExpand});
Chat.Input.PlaceHolder = localization.GetString("Say something!");
}
{
var rightVBox = new VBoxContainer {SizeFlagsHorizontal = SizeFlags.FillExpand};
hBox.AddChild(rightVBox);
rightVBox.AddChild(new Label
{
Text = localization.GetString("Online Players:")
});
rightVBox.AddChild(OnlinePlayerItemList = new ItemList
{
SizeFlagsVertical = SizeFlags.FillExpand,
//SelectMode = ItemList.ItemListSelectMode.None
});
rightVBox.AddChild(new Placeholder(resourceCache)
{
SizeFlagsVertical = SizeFlags.FillExpand,
PlaceholderText = localization.GetString("Server Info\nPlaceholder")
});
}
}
}
}

View File

@@ -1,487 +0,0 @@
using Content.Client.GameObjects.EntitySystems;
using Content.Client.Utility;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
public sealed class NanoStyle
{
public const string StyleClassLabelHeading = "LabelHeading";
public const string StyleClassLabelSubText = "LabelSubText";
public const string StyleClassButtonBig = "ButtonBig";
private static readonly Color NanoGold = Color.FromHex("#A88B5E");
//Used by the APC and SMES menus
public const string StyleClassPowerStateNone = "PowerStateNone";
public const string StyleClassPowerStateLow = "PowerStateLow";
public const string StyleClassPowerStateGood = "PowerStateGood";
public Stylesheet Stylesheet { get; }
public NanoStyle()
{
var resCache = IoCManager.Resolve<IResourceCache>();
var notoSans10 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 10);
var notoSans12 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 12);
var notoSansDisplayBold14 = resCache.GetFont("/Fonts/NotoSansDisplay/NotoSansDisplay-Bold.ttf", 14);
var notoSans16 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 16);
var notoSansBold16 = resCache.GetFont("/Nano/NotoSans/NotoSans-Bold.ttf", 16);
var textureCloseButton = resCache.GetTexture("/Nano/cross.svg.png");
var windowHeaderTex = resCache.GetTexture("/Nano/window_header.png");
var windowHeader = new StyleBoxTexture
{
Texture = windowHeaderTex,
PatchMarginBottom = 3,
ExpandMarginBottom = 3,
};
var windowBackgroundTex = resCache.GetTexture("/Nano/window_background.png");
var windowBackground = new StyleBoxTexture
{
Texture = windowBackgroundTex,
};
windowBackground.SetPatchMargin(StyleBox.Margin.Horizontal | StyleBox.Margin.Bottom, 2);
windowBackground.SetExpandMargin(StyleBox.Margin.Horizontal | StyleBox.Margin.Bottom, 2);
var buttonNormalTex = resCache.GetTexture("/Nano/button_normal.png");
var buttonNormal = new StyleBoxTexture
{
Texture = buttonNormalTex,
};
buttonNormal.SetPatchMargin(StyleBox.Margin.All, 2);
buttonNormal.SetContentMarginOverride(StyleBox.Margin.Horizontal, 8);
var buttonHoverTex = resCache.GetTexture("/Nano/button_hover.png");
var buttonHover = new StyleBoxTexture
{
Texture = buttonHoverTex,
};
buttonHover.SetPatchMargin(StyleBox.Margin.All, 2);
buttonHover.SetContentMarginOverride(StyleBox.Margin.Horizontal, 8);
var buttonPressedTex = resCache.GetTexture("/Nano/button_pressed.png");
var buttonPressed = new StyleBoxTexture
{
Texture = buttonPressedTex,
};
buttonPressed.SetPatchMargin(StyleBox.Margin.All, 2);
buttonPressed.SetContentMarginOverride(StyleBox.Margin.Horizontal, 8);
var buttonDisabledTex = resCache.GetTexture("/Nano/button_disabled.png");
var buttonDisabled = new StyleBoxTexture
{
Texture = buttonDisabledTex,
};
buttonDisabled.SetPatchMargin(StyleBox.Margin.All, 2);
buttonDisabled.SetContentMarginOverride(StyleBox.Margin.Horizontal, 8);
var lineEditTex = resCache.GetTexture("/Nano/lineedit.png");
var lineEdit = new StyleBoxTexture
{
Texture = lineEditTex,
};
lineEdit.SetPatchMargin(StyleBox.Margin.All, 3);
lineEdit.SetContentMarginOverride(StyleBox.Margin.Horizontal, 5);
var tabContainerPanelTex = resCache.GetTexture("/Nano/tabcontainer_panel.png");
var tabContainerPanel = new StyleBoxTexture
{
Texture = tabContainerPanelTex,
};
tabContainerPanel.SetPatchMargin(StyleBox.Margin.All, 2);
var tabContainerBoxActive = new StyleBoxFlat {BackgroundColor = new Color(64, 64, 64)};
tabContainerBoxActive.SetContentMarginOverride(StyleBox.Margin.Horizontal, 3);
var tabContainerBoxInactive = new StyleBoxFlat {BackgroundColor = new Color(32, 32, 32)};
tabContainerBoxInactive.SetContentMarginOverride(StyleBox.Margin.Horizontal, 3);
var vScrollBarGrabberNormal = new StyleBoxFlat
{
BackgroundColor = Color.Gray.WithAlpha(0.35f), ContentMarginLeftOverride = 10
};
var vScrollBarGrabberHover = new StyleBoxFlat
{
BackgroundColor = new Color(140, 140, 140).WithAlpha(0.35f), ContentMarginLeftOverride = 10
};
var vScrollBarGrabberGrabbed = new StyleBoxFlat
{
BackgroundColor = new Color(160, 160, 160).WithAlpha(0.35f), ContentMarginLeftOverride = 10
};
var hScrollBarGrabberNormal = new StyleBoxFlat
{
BackgroundColor = Color.Gray.WithAlpha(0.35f), ContentMarginTopOverride = 10
};
var hScrollBarGrabberHover = new StyleBoxFlat
{
BackgroundColor = new Color(140, 140, 140).WithAlpha(0.35f), ContentMarginTopOverride = 10
};
var hScrollBarGrabberGrabbed = new StyleBoxFlat
{
BackgroundColor = new Color(160, 160, 160).WithAlpha(0.35f), ContentMarginTopOverride = 10
};
var progressBarBackground = new StyleBoxFlat
{
BackgroundColor = new Color(0.25f, 0.25f, 0.25f)
};
progressBarBackground.SetContentMarginOverride(StyleBox.Margin.Vertical, 5);
var progressBarForeground = new StyleBoxFlat
{
BackgroundColor = new Color(0.25f, 0.50f, 0.25f)
};
progressBarForeground.SetContentMarginOverride(StyleBox.Margin.Vertical, 5);
// CheckBox
var checkBoxTextureChecked = resCache.GetTexture("/Nano/checkbox_checked.svg.96dpi.png");
var checkBoxTextureUnchecked = resCache.GetTexture("/Nano/checkbox_unchecked.svg.96dpi.png");
// Tooltip box
var tooltipTexture = resCache.GetTexture("/Nano/tooltip.png");
var tooltipBox = new StyleBoxTexture
{
Texture = tooltipTexture,
};
tooltipBox.SetPatchMargin(StyleBox.Margin.All, 2);
tooltipBox.SetContentMarginOverride(StyleBox.Margin.Horizontal, 5);
// Placeholder
var placeholderTexture = resCache.GetTexture("/Nano/placeholder.png");
var placeholder = new StyleBoxTexture { Texture = placeholderTexture };
placeholder.SetPatchMargin(StyleBox.Margin.All, 24);
placeholder.SetExpandMargin(StyleBox.Margin.All, -5);
var itemListBackgroundSelected = new StyleBoxFlat {BackgroundColor = new Color(75, 75, 86)};
itemListBackgroundSelected.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListBackgroundSelected.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
var itemListItemBackgroundDisabled = new StyleBoxFlat {BackgroundColor = new Color(10, 10, 12)};
itemListItemBackgroundDisabled.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListItemBackgroundDisabled.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
var itemListItemBackground = new StyleBoxFlat {BackgroundColor = new Color(55, 55, 68)};
itemListItemBackground.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListItemBackground.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
Stylesheet = new Stylesheet(new[]
{
// Default font.
new StyleRule(
new SelectorElement(null, null, null, null),
new[]
{
new StyleProperty("font", notoSans12),
}),
// Window title.
new StyleRule(
new SelectorElement(typeof(Label), new[] {SS14Window.StyleClassWindowTitle}, null, null),
new[]
{
new StyleProperty(Label.StylePropertyFontColor, NanoGold),
new StyleProperty(Label.StylePropertyFont, notoSansDisplayBold14),
}),
// Window background.
new StyleRule(
new SelectorElement(null, new[] {SS14Window.StyleClassWindowPanel}, null, null),
new[]
{
new StyleProperty(Panel.StylePropertyPanel, windowBackground),
}),
// Window header.
new StyleRule(
new SelectorElement(typeof(Panel), new[] {SS14Window.StyleClassWindowHeader}, null, null),
new[]
{
new StyleProperty(Panel.StylePropertyPanel, windowHeader),
}),
// Window close button base texture.
new StyleRule(
new SelectorElement(typeof(TextureButton), new[] {SS14Window.StyleClassWindowCloseButton}, null,
null),
new[]
{
new StyleProperty(TextureButton.StylePropertyTexture, textureCloseButton),
new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#4B596A")),
}),
// Window close button hover.
new StyleRule(
new SelectorElement(typeof(TextureButton), new[] {SS14Window.StyleClassWindowCloseButton}, null,
TextureButton.StylePseudoClassHover),
new[]
{
new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#7F3636")),
}),
// Window close button pressed.
new StyleRule(
new SelectorElement(typeof(TextureButton), new[] {SS14Window.StyleClassWindowCloseButton}, null,
TextureButton.StylePseudoClassPressed),
new[]
{
new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#753131")),
}),
// Regular buttons!
new StyleRule(
new SelectorElement(typeof(Button), null, null, Button.StylePseudoClassNormal),
new[]
{
new StyleProperty(Button.StylePropertyStyleBox, buttonNormal),
}),
new StyleRule(
new SelectorElement(typeof(Button), null, null, Button.StylePseudoClassHover),
new[]
{
new StyleProperty(Button.StylePropertyStyleBox, buttonHover),
}),
new StyleRule(
new SelectorElement(typeof(Button), null, null, Button.StylePseudoClassPressed),
new[]
{
new StyleProperty(Button.StylePropertyStyleBox, buttonPressed),
}),
new StyleRule(
new SelectorElement(typeof(Button), null, null, Button.StylePseudoClassDisabled),
new[]
{
new StyleProperty(Button.StylePropertyStyleBox, buttonDisabled),
new StyleProperty("font-color", Color.FromHex("#E5E5E581")),
}),
// Main menu: Make those buttons bigger.
new StyleRule(
new SelectorChild(
new SelectorElement(null, null, "mainMenuVBox", null),
new SelectorElement(typeof(Button), null, null, null)),
new[]
{
new StyleProperty("font", notoSansBold16),
}),
// Main menu: also make those buttons slightly more separated.
new StyleRule(new SelectorElement(typeof(BoxContainer), null, "mainMenuVBox", null),
new[]
{
new StyleProperty(BoxContainer.StylePropertySeparation, 2),
}),
// Fancy LineEdit
new StyleRule(new SelectorElement(typeof(LineEdit), null, null, null),
new[]
{
new StyleProperty(LineEdit.StylePropertyStyleBox, lineEdit),
}),
new StyleRule(
new SelectorElement(typeof(LineEdit), new[] {LineEdit.StyleClassLineEditNotEditable}, null, null),
new[]
{
new StyleProperty("font-color", new Color(192, 192, 192)),
}),
new StyleRule(new SelectorElement(typeof(LineEdit), null, null, LineEdit.StylePseudoClassPlaceholder),
new[]
{
new StyleProperty("font-color", Color.Gray),
}),
// TabContainer
new StyleRule(new SelectorElement(typeof(TabContainer), null, null, null),
new[]
{
new StyleProperty(TabContainer.StylePropertyPanelStyleBox, tabContainerPanel),
new StyleProperty(TabContainer.StylePropertyTabStyleBox, tabContainerBoxActive),
new StyleProperty(TabContainer.StylePropertyTabStyleBoxInactive, tabContainerBoxInactive),
}),
// Scroll bars
new StyleRule(new SelectorElement(typeof(VScrollBar), null, null, null),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
vScrollBarGrabberNormal),
}),
new StyleRule(new SelectorElement(typeof(VScrollBar), null, null, ScrollBar.StylePseudoClassHover),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
vScrollBarGrabberHover),
}),
new StyleRule(new SelectorElement(typeof(VScrollBar), null, null, ScrollBar.StylePseudoClassGrabbed),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
vScrollBarGrabberGrabbed),
}),
new StyleRule(new SelectorElement(typeof(HScrollBar), null, null, null),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
hScrollBarGrabberNormal),
}),
new StyleRule(new SelectorElement(typeof(HScrollBar), null, null, ScrollBar.StylePseudoClassHover),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
hScrollBarGrabberHover),
}),
new StyleRule(new SelectorElement(typeof(HScrollBar), null, null, ScrollBar.StylePseudoClassGrabbed),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
hScrollBarGrabberGrabbed),
}),
// ProgressBar
new StyleRule(new SelectorElement(typeof(ProgressBar), null, null, null),
new[]
{
new StyleProperty(ProgressBar.StylePropertyBackground, progressBarBackground),
new StyleProperty(ProgressBar.StylePropertyForeground, progressBarForeground)
}),
// CheckBox
new StyleRule(new SelectorElement(typeof(CheckBox), null, null, null), new[]
{
new StyleProperty(CheckBox.StylePropertyIcon, checkBoxTextureUnchecked),
}),
new StyleRule(new SelectorElement(typeof(CheckBox), null, null, Button.StylePseudoClassPressed), new[]
{
new StyleProperty(CheckBox.StylePropertyIcon, checkBoxTextureChecked),
}),
new StyleRule(new SelectorElement(typeof(CheckBox), null, null, null), new[]
{
new StyleProperty(CheckBox.StylePropertyHSeparation, 3),
}),
// Tooltip
new StyleRule(new SelectorElement(typeof(Tooltip), null, null, null), new[]
{
new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox)
}),
new StyleRule(new SelectorElement(typeof(PanelContainer), new []{"tooltipBox"}, null, null), new[]
{
new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox)
}),
// Entity tooltip
new StyleRule(
new SelectorElement(typeof(PanelContainer), new[] {ExamineSystem.StyleClassEntityTooltip}, null,
null), new[]
{
new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox)
}),
// ItemList
new StyleRule(new SelectorElement(typeof(ItemList), null, null, null), new[]
{
new StyleProperty(ItemList.StylePropertyBackground,
new StyleBoxFlat {BackgroundColor = new Color(32, 32, 40)}),
new StyleProperty(ItemList.StylePropertyItemBackground,
itemListItemBackground),
new StyleProperty(ItemList.StylePropertyDisabledItemBackground,
itemListItemBackgroundDisabled),
new StyleProperty(ItemList.StylePropertySelectedItemBackground,
itemListBackgroundSelected)
}),
// Tree
new StyleRule(new SelectorElement(typeof(Tree), null, null, null), new[]
{
new StyleProperty(Tree.StylePropertyBackground,
new StyleBoxFlat {BackgroundColor = new Color(32, 32, 40)}),
new StyleProperty(Tree.StylePropertyItemBoxSelected, new StyleBoxFlat
{
BackgroundColor = new Color(55, 55, 68),
ContentMarginLeftOverride = 4
})
}),
// Placeholder
new StyleRule(new SelectorElement(typeof(Placeholder), null, null, null), new []
{
new StyleProperty(PanelContainer.StylePropertyPanel, placeholder),
}),
new StyleRule(new SelectorElement(typeof(Label), new []{Placeholder.StyleClassPlaceholderText}, null, null), new []
{
new StyleProperty(Label.StylePropertyFont, notoSans16),
new StyleProperty(Label.StylePropertyFontColor, new Color(103, 103, 103, 128)),
}),
// Big Label
new StyleRule(new SelectorElement(typeof(Label), new []{StyleClassLabelHeading}, null, null), new []
{
new StyleProperty(Label.StylePropertyFont, notoSansBold16),
new StyleProperty(Label.StylePropertyFontColor, NanoGold),
} ),
// Small Label
new StyleRule(new SelectorElement(typeof(Label), new []{StyleClassLabelSubText}, null, null), new []
{
new StyleProperty(Label.StylePropertyFont, notoSans10),
new StyleProperty(Label.StylePropertyFontColor, Color.DarkGray),
} ),
// Big Button
new StyleRule(new SelectorElement(typeof(Button), new []{StyleClassButtonBig}, null, null), new []
{
new StyleProperty("font", notoSans16)
}),
//APC and SMES power state label colors
new StyleRule(new SelectorElement(typeof(Label), new []{StyleClassPowerStateNone}, null, null), new []
{
new StyleProperty(Label.StylePropertyFontColor, new Color(0.8f, 0.0f, 0.0f))
}),
new StyleRule(new SelectorElement(typeof(Label), new []{StyleClassPowerStateLow}, null, null), new []
{
new StyleProperty(Label.StylePropertyFontColor, new Color(0.9f, 0.36f, 0.0f))
}),
new StyleRule(new SelectorElement(typeof(Label), new []{StyleClassPowerStateGood}, null, null), new []
{
new StyleProperty(Label.StylePropertyFontColor, new Color(0.024f, 0.8f, 0.0f))
}),
// Those top menu buttons.
new StyleRule(
new SelectorElement(typeof(GameHud.TopButton), null, null, Button.StylePseudoClassNormal), new []
{
new StyleProperty(Button.StylePropertyStyleBox, buttonNormal),
}),
new StyleRule(
new SelectorElement(typeof(GameHud.TopButton), null, null, Button.StylePseudoClassPressed), new []
{
new StyleProperty(Button.StylePropertyStyleBox, buttonPressed),
}),
new StyleRule(
new SelectorElement(typeof(GameHud.TopButton), null, null, Button.StylePseudoClassHover), new []
{
new StyleProperty(Button.StylePropertyStyleBox, buttonHover),
}),
new StyleRule(
new SelectorElement(typeof(Label), new [] {GameHud.TopButton.StyleClassLabelTopButton}, null, null), new []
{
new StyleProperty(Label.StylePropertyFont, notoSansDisplayBold14),
}),
});
}
}
}

View File

@@ -1,31 +0,0 @@
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.UserInterface
{
public sealed class Placeholder : PanelContainer
{
public const string StyleClassPlaceholderText = "PlaceholderText";
private readonly Label _label;
public string PlaceholderText
{
get => _label.Text;
set => _label.Text = value;
}
public Placeholder(IResourceCache _resourceCache)
{
_label = new Label
{
SizeFlagsHorizontal = SizeFlags.Fill,
SizeFlagsVertical = SizeFlags.Fill,
Align = Label.AlignMode.Center,
VAlign = Label.VAlignMode.Center
};
_label.AddStyleClass(StyleClassPlaceholderText);
AddChild(_label);
}
}
}

Some files were not shown because too many files have changed in this diff Show More