Compare commits

..

12 Commits

Author SHA1 Message Date
Westin Miller
9471d83a45 Merge pull request #108 from TorchAPI/staging
Prepare Release v1.2.0
2017-09-07 19:56:23 -07:00
Westin Miller
52b225d944 Merge branch 'master' into staging 2017-09-07 15:39:04 -07:00
Westin Miller
c8f0a61209 Provide DS config path to Save
This keeps MyFileSystem from getting initialized too early.
2017-09-07 14:54:57 -07:00
John Gross
59c3e9eb54 Merge pull request #107 from TorchAPI/patch-96
Proper scrolling and formatting for the ChatPanel.
2017-09-07 13:39:15 -04:00
Westin Miller
d20d68b831 Proper scrolling and formatting for the ChatPanel.
- Users are blue, server is dark blue.
- Autoscroll when it's scrolled to the bottom, else leave it alone.
2017-09-07 02:54:10 -07:00
Westin Miller
cfda1f8eef Fixes issues with the assembly resolver getting disposed when launched in nogui mode.
This should solve #102, #104.
2017-09-07 02:03:48 -07:00
Westin Miller
2fb222125a Merge pull request #106 from TorchAPI/reflected-internals
Specify internal types by Assembly Qualified Name for reflection
2017-09-06 20:58:29 -07:00
John Gross
c7c3c00783 Merge branch 'staging' into reflected-internals 2017-09-06 23:57:34 -04:00
Westin Miller
dcc130e2cf Fixed bad exit code.
Fixed creds GUID
2017-09-06 20:33:37 -07:00
Westin Miller
491f3d3af4 Auto-release 2017-08-31 19:36:01 -07:00
Westin Miller
178fcb8164 Specify internal types by Assembly Qualified Name for reflection 2017-08-31 16:22:38 -07:00
John Gross
64f123abe9 Specify PR base branch 2017-08-27 09:08:50 -07:00
8 changed files with 102 additions and 47 deletions

View File

@@ -1,9 +1,9 @@
# Making a Pull Request # Making a Pull Request
* Fork this repository and make sure your local **master** branch is up to date with the main repository. * Fork this repository and make sure your local **staging** branch is up to date with the main repository.
* Create a new branch for your addition with an appropriate name, e.g. **add-restart-command** * Create a new branch from the **staging** branch for your addition with an appropriate name, e.g. **add-restart-command**
* PRs work by submitting the *entire* branch, so this allows you to continue work without locking up your whole repository. * PRs work by submitting the *entire* branch, so this allows you to continue work without locking up your whole repository.
* Commit your changes to that branch, making sure that you **follow the code guidelines below**. * Commit your changes to that branch, making sure that you **follow the code guidelines below**.
* Submit your branch as a PR to be reviewed. * Submit your branch as a PR to be reviewed, with Torch's **staging** branch as the base.
## Naming Conventions ## Naming Conventions
* Types: **PascalCase** * Types: **PascalCase**

View File

@@ -16,7 +16,7 @@ try
tag_name=$tagName tag_name=$tagName
name="Generated $tagName" name="Generated $tagName"
body="" body=""
draft=$FALSE draft=$TRUE
prerelease=$tagName.Contains("alpha") -or $tagName.Contains("beta") prerelease=$tagName.Contains("alpha") -or $tagName.Contains("beta")
} }
Write-Output("Creating new release " + $tagName + "...") Write-Output("Creating new release " + $tagName + "...")

4
Jenkinsfile vendored
View File

@@ -59,8 +59,8 @@ node {
gitSimpleVersion = bat(returnStdout: true, script: "@git describe --tags --abbrev=0").trim() gitSimpleVersion = bat(returnStdout: true, script: "@git describe --tags --abbrev=0").trim()
if (gitVersion == gitSimpleVersion) { if (gitVersion == gitSimpleVersion) {
stage('Release') { stage('Release') {
withCredentials([usernamePassword(credentialsId: 'e771beac-b3ee-4bc9-82b7-40a6d426d508', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) { withCredentials([usernamePassword(credentialsId: 'torch-github', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
powershell "./Jenkins/release.ps1 \"https://api.github.com/repos/TorchAPI/Torch/\" \"$gitSimpleVersion\" \"$USERNAME:$PASSWORD\" @(\"bin/torch-server.zip\", \"bin/torch-client.zip\")" powershell "& ./Jenkins/release.ps1 \"https://api.github.com/repos/TorchAPI/Torch/\" \"$gitSimpleVersion\" \"$USERNAME:$PASSWORD\" @(\"bin/torch-server.zip\", \"bin/torch-client.zip\")"
} }
} }
} }

View File

@@ -8,6 +8,7 @@ using System.Net;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Threading;
using NLog; using NLog;
using Torch.Utils; using Torch.Utils;
@@ -84,15 +85,15 @@ quit";
_server = new TorchServer(_config); _server = new TorchServer(_config);
_server.Init(); _server.Init();
if (_config.NoGui || _config.Autostart)
{
new Thread(_server.Start).Start();
}
if (!_config.NoGui) if (!_config.NoGui)
{ {
new TorchUI(_server).ShowDialog(); var ui = new TorchUI(_server);
if (_config.Autostart)
new Thread(_server.Start).Start();
ui.ShowDialog();
} }
else
_server.Start();
_resolver?.Dispose(); _resolver?.Dispose();
} }

View File

@@ -131,7 +131,7 @@ namespace Torch.Server.Managers
public void SaveConfig() public void SaveConfig()
{ {
DedicatedConfig.Save(); DedicatedConfig.Save(Path.Combine(Torch.Config.InstancePath, CONFIG_NAME));
Log.Info("Saved dedicated config."); Log.Info("Saved dedicated config.");
try try

View File

@@ -10,20 +10,9 @@
<RowDefinition/> <RowDefinition/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<ListView Grid.Row="0" x:Name="ChatItems" ItemsSource="{Binding ChatHistory}" Margin="5,5,5,5"> <ScrollViewer x:Name="ChatScroller" Grid.Row="0" Margin="5,5,5,5" HorizontalScrollBarVisibility="Disabled">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"/> <TextBlock x:Name="ChatItems" />
<ListView.ItemTemplate> </ScrollViewer>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding Timestamp}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
<TextBlock Text=": "/>
<TextBlock Text="{Binding Message}"/>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Grid Grid.Row="1"> <Grid Grid.Row="1">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition/> <ColumnDefinition/>

View File

@@ -41,23 +41,32 @@ namespace Torch.Server
{ {
_server = (TorchBase)server; _server = (TorchBase)server;
_multiplayer = (MultiplayerManager)server.Multiplayer; _multiplayer = (MultiplayerManager)server.Multiplayer;
ChatItems.Items.Clear();
DataContext = _multiplayer; DataContext = _multiplayer;
ChatItems.Inlines.Clear();
_multiplayer.ChatHistory.ForEach(InsertMessage);
if (_multiplayer.ChatHistory is INotifyCollectionChanged ncc) if (_multiplayer.ChatHistory is INotifyCollectionChanged ncc)
ncc.CollectionChanged += ChatHistory_CollectionChanged; ncc.CollectionChanged += ChatHistory_CollectionChanged;
ChatScroller.ScrollToBottom();
} }
private void ChatHistory_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) private void ChatHistory_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{ {
ChatItems.ScrollToItem(ChatItems.Items.Count - 1); foreach (IChatMessage msg in e.NewItems)
/* InsertMessage(msg);
if (VisualTreeHelper.GetChildrenCount(ChatItems) > 0) }
{
Border border = (Border)VisualTreeHelper.GetChild(ChatItems, 0); private void InsertMessage(IChatMessage msg)
ScrollViewer scrollViewer = (ScrollViewer)VisualTreeHelper.GetChild(border, 0); {
scrollViewer.ScrollToBottom(); bool atBottom = ChatScroller.VerticalOffset + 8 > ChatScroller.ScrollableHeight;
}*/ var span = new Span();
span.Inlines.Add($"{msg.Timestamp} ");
span.Inlines.Add(new Run(msg.Name) { Foreground = msg.Name == "Server" ? Brushes.DarkBlue : Brushes.Blue });
span.Inlines.Add($": {msg.Message}");
span.Inlines.Add(new LineBreak());
ChatItems.Inlines.Add(span);
if (atBottom)
ChatScroller.ScrollToBottom();
} }
private void SendButton_Click(object sender, RoutedEventArgs e) private void SendButton_Click(object sender, RoutedEventArgs e)

View File

@@ -23,6 +23,15 @@ namespace Torch.Utils
/// Declaring type of the member to access. If null, inferred from the instance argument type. /// Declaring type of the member to access. If null, inferred from the instance argument type.
/// </summary> /// </summary>
public Type Type { get; set; } = null; public Type Type { get; set; } = null;
/// <summary>
/// Assembly qualified name of <see cref="Type"/>
/// </summary>
public string TypeName
{
get => Type?.AssemblyQualifiedName;
set => Type = value == null ? null : Type.GetType(value, true);
}
} }
/// <summary> /// <summary>
@@ -93,6 +102,19 @@ namespace Torch.Utils
[AttributeUsage(AttributeTargets.Field)] [AttributeUsage(AttributeTargets.Field)]
public class ReflectedMethodAttribute : ReflectedMemberAttribute public class ReflectedMethodAttribute : ReflectedMemberAttribute
{ {
/// <summary>
/// When set the parameters types for the method are assumed to be this.
/// </summary>
public Type[] OverrideTypes { get; set; }
/// <summary>
/// Assembly qualified names of <see cref="OverrideTypes"/>
/// </summary>
public string[] OverrideTypeNames
{
get => OverrideTypes.Select(x => x.AssemblyQualifiedName).ToArray();
set => OverrideTypes = value?.Select(x => x == null ? null : Type.GetType(x)).ToArray();
}
} }
/// <summary> /// <summary>
@@ -232,10 +254,14 @@ namespace Torch.Utils
trueParameterTypes = parameters.Skip(1).Select(x => x.ParameterType).ToArray(); trueParameterTypes = parameters.Skip(1).Select(x => x.ParameterType).ToArray();
} }
var invokeTypes = new Type[trueParameterTypes.Length];
for (var i = 0; i < invokeTypes.Length; i++)
invokeTypes[i] = attr.OverrideTypes?[i] ?? trueParameterTypes[i];
MethodInfo methodInstance = trueType.GetMethod(attr.Name ?? field.Name, MethodInfo methodInstance = trueType.GetMethod(attr.Name ?? field.Name,
(attr is ReflectedStaticMethodAttribute ? BindingFlags.Static : BindingFlags.Instance) | (attr is ReflectedStaticMethodAttribute ? BindingFlags.Static : BindingFlags.Instance) |
BindingFlags.Public | BindingFlags.Public |
BindingFlags.NonPublic, null, CallingConventions.Any, trueParameterTypes, null); BindingFlags.NonPublic, null, CallingConventions.Any, invokeTypes, null);
if (methodInstance == null) if (methodInstance == null)
{ {
string methodType = attr is ReflectedStaticMethodAttribute ? "static" : "instance"; string methodType = attr is ReflectedStaticMethodAttribute ? "static" : "instance";
@@ -245,13 +271,38 @@ namespace Torch.Utils
$"Unable to find {methodType} method {attr.Name ?? field.Name} in type {trueType.FullName} with parameters {methodParams}"); $"Unable to find {methodType} method {attr.Name ?? field.Name} in type {trueType.FullName} with parameters {methodParams}");
} }
if (attr is ReflectedStaticMethodAttribute) if (attr is ReflectedStaticMethodAttribute)
{
if (attr.OverrideTypes != null)
{
ParameterExpression[] paramExp =
parameters.Select(x => Expression.Parameter(x.ParameterType)).ToArray();
var argExp = new Expression[invokeTypes.Length];
for (var i = 0; i < argExp.Length; i++)
if (invokeTypes[i] != paramExp[i].Type)
argExp[i] = Expression.Convert(paramExp[i], invokeTypes[i]);
else
argExp[i] = paramExp[i];
field.SetValue(null,
Expression.Lambda(Expression.Call(methodInstance, argExp), paramExp)
.Compile());
}
else
field.SetValue(null, Delegate.CreateDelegate(field.FieldType, methodInstance)); field.SetValue(null, Delegate.CreateDelegate(field.FieldType, methodInstance));
}
else else
{ {
ParameterExpression[] paramExp = parameters.Select(x => Expression.Parameter(x.ParameterType)).ToArray(); ParameterExpression[] paramExp =
parameters.Select(x => Expression.Parameter(x.ParameterType)).ToArray();
var argExp = new Expression[invokeTypes.Length];
for (var i = 0; i < argExp.Length; i++)
if (invokeTypes[i] != paramExp[i + 1].Type)
argExp[i] = Expression.Convert(paramExp[i + 1], invokeTypes[i]);
else
argExp[i] = paramExp[i + 1];
field.SetValue(null, field.SetValue(null,
Expression.Lambda(Expression.Call(paramExp[0], methodInstance, paramExp.Skip(1)), paramExp) Expression.Lambda(Expression.Call(paramExp[0], methodInstance, argExp), paramExp)
.Compile()); .Compile());
} }
} }
@@ -287,7 +338,7 @@ namespace Torch.Utils
if (trueType == null && isStatic) if (trueType == null && isStatic)
throw new ArgumentException("Static field setters need their type defined", nameof(field)); throw new ArgumentException("Static field setters need their type defined", nameof(field));
if (!isStatic) if (!isStatic && trueType == null)
trueType = parameters[0].ParameterType; trueType = parameters[0].ParameterType;
} }
else if (attr is ReflectedGetterAttribute) else if (attr is ReflectedGetterAttribute)
@@ -300,7 +351,7 @@ namespace Torch.Utils
if (trueType == null && isStatic) if (trueType == null && isStatic)
throw new ArgumentException("Static field getters need their type defined", nameof(field)); throw new ArgumentException("Static field getters need their type defined", nameof(field));
if (!isStatic) if (!isStatic && trueType == null)
trueType = parameters[0].ParameterType; trueType = parameters[0].ParameterType;
} }
else else
@@ -318,10 +369,15 @@ namespace Torch.Utils
$"Unable to find field or property for {trueName} in {trueType.FullName} or its base types", nameof(field)); $"Unable to find field or property for {trueName} in {trueType.FullName} or its base types", nameof(field));
ParameterExpression[] paramExp = parameters.Select(x => Expression.Parameter(x.ParameterType)).ToArray(); ParameterExpression[] paramExp = parameters.Select(x => Expression.Parameter(x.ParameterType)).ToArray();
Expression instanceExpr = null;
if (!isStatic)
{
instanceExpr = trueType == paramExp[0].Type ? (Expression) paramExp[0] : Expression.Convert(paramExp[0], trueType);
}
MemberExpression fieldExp = sourceField != null MemberExpression fieldExp = sourceField != null
? Expression.Field(isStatic ? null : paramExp[0], sourceField) ? Expression.Field(instanceExpr, sourceField)
: Expression.Property(isStatic ? null : paramExp[0], sourceProperty); : Expression.Property(instanceExpr, sourceProperty);
Expression impl; Expression impl;
if (attr is ReflectedSetterAttribute) if (attr is ReflectedSetterAttribute)
{ {