Compare commits
81 Commits
v1.11.0
...
e201281c36
Author | SHA1 | Date | |
---|---|---|---|
e201281c36 | |||
cbd81f92f4 | |||
![]() |
f364754092 | ||
8b760e5e9b | |||
3b2bfbb0e6 | |||
2c8691e9ae | |||
![]() |
e6a2d26671 | ||
fafff8090f | |||
![]() |
b37016a49c | ||
6e8c1d4a15 | |||
92f5289576 | |||
![]() |
c62b46850c | ||
3d160f9b90 | |||
79efb9bd51 | |||
ef3c85c6d3 | |||
![]() |
e61fc45ad2 | ||
de53f682f0 | |||
3ddfa189e9 | |||
ddc588c792 | |||
984afbdf0b | |||
56a72ad940 | |||
b62c539bdd | |||
d9272acb44 | |||
5c89eb5a58 | |||
583041c295 | |||
ded10d175f | |||
380682d175 | |||
055bddc22c | |||
5b2442591f | |||
3eb1a08697 | |||
79283f4039 | |||
497b828f2d | |||
41dc3e8fc4 | |||
eb1be4cdb8 | |||
d4655c1e50 | |||
b1debe0aab | |||
f5780a4366 | |||
101e3c5ffc | |||
97b3a57ee1 | |||
0788a32158 | |||
f553ddddd8 | |||
07fb477c3a | |||
f8b920100d | |||
cfdca6f031 | |||
085669e43a | |||
eda70a2aae | |||
c2be92c41b | |||
4bcd23389d | |||
2a51fcb47d | |||
2c2f05c5b2 | |||
ab92469f11 | |||
749f324f7d | |||
1c49c41b71 | |||
1993d3d295 | |||
dce7e54675 | |||
41c644f2af | |||
78be273c7a | |||
c94a7683e4 | |||
b407012bef | |||
bb7d28153f | |||
627d9c7cd2 | |||
53a83fd7a7 | |||
c2ca091662 | |||
738a755353 | |||
dcbd946407 | |||
2a8cebcbb5 | |||
434ec7b2df | |||
c2ff37facf | |||
f48c9b4d0b | |||
1d734479d1 | |||
a989581d59 | |||
6ab9d3842c | |||
b69b2941b6 | |||
90deaa84b4 | |||
403cc3fe52 | |||
dd4eb36c17 | |||
2645e16bee | |||
82668c4c6a | |||
8fce4a8995 | |||
![]() |
4cfbebcc5a | ||
40db4236ba |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 37 KiB |
BIN
Doc/Screenshots-en/22-Proxy.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
Doc/Screenshots-en/23-SceneTag.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
Doc/Screenshots-en/24-Weather.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
Doc/Screenshots-en/25-Settings.png
Normal file
After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 41 KiB |
BIN
Doc/Screenshots/22-Proxy.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
Doc/Screenshots/23-SceneTag.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
Doc/Screenshots/24-Weather.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
Doc/Screenshots/25-Settings.png
Normal file
After Width: | Height: | Size: 32 KiB |
18
README.md
@@ -34,9 +34,27 @@ The server require [gc-opencommand-plugin](https://github.com/jie65535/gc-openco
|
||||
|
||||
## Update log
|
||||
|
||||
### GrasscutterTools-v1.13
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### GrasscutterTools-v1.11
|
||||

|
||||
|
||||
Commandline Usages:
|
||||
```bash
|
||||
GcTools.exe -help
|
||||
GcTools.exe -version
|
||||
GcTools.exe -c "cmd arg"
|
||||
GcTools.exe -c "cmd1 arg" && GcTools -c "cmd2 arg1 arg2"
|
||||
GcTools.exe -host http://127.0.0.1:443 -token 123456 -c "cmd1 arg1 arg2 | cmd2 | cmd3 arg"
|
||||
```
|
||||
|
||||
### GrasscutterTools-v1.10
|
||||

|
||||
|
||||
|
@@ -35,9 +35,27 @@ GCG поддерживает 简体中文 (китайский упр.), 繁體
|
||||
|
||||
## Лог обновлений
|
||||
|
||||
### GrasscutterTools-v1.13
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### GrasscutterTools-v1.11
|
||||

|
||||
|
||||
Commandline Usages:
|
||||
```bash
|
||||
GcTools.exe -help
|
||||
GcTools.exe -version
|
||||
GcTools.exe -c "cmd arg"
|
||||
GcTools.exe -c "cmd1 arg" && GcTools -c "cmd2 arg1 arg2"
|
||||
GcTools.exe -host http://127.0.0.1:443 -token 123456 -c "cmd1 arg1 arg2 | cmd2 | cmd3 arg"
|
||||
```
|
||||
|
||||
### GrasscutterTools-v1.10
|
||||

|
||||
|
||||
|
@@ -35,9 +35,27 @@
|
||||
|
||||
## 更新概要
|
||||
|
||||
### GrasscutterTools-v1.13
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### GrasscutterTools-v1.11
|
||||

|
||||
|
||||
命令行用法:
|
||||
```bash
|
||||
GcTools.exe -help
|
||||
GcTools.exe -version
|
||||
GcTools.exe -c "cmd arg"
|
||||
GcTools.exe -c "cmd1 arg" && GcTools -c "cmd2 arg1 arg2"
|
||||
GcTools.exe -host http://127.0.0.1:443 -token 123456 -c "cmd1 arg1 arg2 | cmd2 | cmd3 arg"
|
||||
```
|
||||
|
||||
### GrasscutterTools-v1.10
|
||||

|
||||
|
||||
|
@@ -34,9 +34,27 @@
|
||||
|
||||
## 更新日誌
|
||||
|
||||
### GrasscutterTools-v1.13
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### GrasscutterTools-v1.11
|
||||

|
||||
|
||||
Commandline Usages:
|
||||
```bash
|
||||
GcTools.exe -help
|
||||
GcTools.exe -version
|
||||
GcTools.exe -c "cmd arg"
|
||||
GcTools.exe -c "cmd1 arg" && GcTools -c "cmd2 arg1 arg2"
|
||||
GcTools.exe -host http://127.0.0.1:443 -token 123456 -c "cmd1 arg1 arg2 | cmd2 | cmd3 arg"
|
||||
```
|
||||
|
||||
### GrasscutterTools-v1.10
|
||||

|
||||
|
||||
|
@@ -29,7 +29,7 @@
|
||||
<value>10001</value>
|
||||
</setting>
|
||||
<setting name="Host" serializeAs="String">
|
||||
<value>https://127.0.0.1</value>
|
||||
<value>http://127.0.0.1:443</value>
|
||||
</setting>
|
||||
<setting name="CheckedLastVersion" serializeAs="String">
|
||||
<value />
|
||||
@@ -76,6 +76,15 @@
|
||||
<setting name="IsUpgraded" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="IsHotkeyEenabled" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="AutoStartProxy" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="WindowOpacity" serializeAs="String">
|
||||
<value>100</value>
|
||||
</setting>
|
||||
</GrasscutterTools.Properties.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
@@ -24,7 +24,7 @@ using GrasscutterTools.Utils;
|
||||
|
||||
namespace GrasscutterTools.DispatchServer
|
||||
{
|
||||
public static class DispatchServerAPI
|
||||
internal static class DispatchServerAPI
|
||||
{
|
||||
public static async Task<ServerStatus> QueryServerStatus(string host)
|
||||
{
|
||||
|
@@ -21,7 +21,7 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.DispatchServer.Model
|
||||
{
|
||||
public class ServerStatus
|
||||
internal class ServerStatus
|
||||
{
|
||||
[JsonProperty("playerCount")]
|
||||
public int PlayerCount { get; set; }
|
||||
@@ -33,7 +33,7 @@ namespace GrasscutterTools.DispatchServer.Model
|
||||
public string Version { get; set; }
|
||||
}
|
||||
|
||||
public class ServerStatusResponse
|
||||
internal class ServerStatusResponse
|
||||
{
|
||||
[JsonProperty("retcode")]
|
||||
public int RetCode { get; set; }
|
||||
|
202
Source/GrasscutterTools/Eavesdrop/Certifier.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace Eavesdrop;
|
||||
|
||||
public sealed class Certifier : IDisposable
|
||||
{
|
||||
private readonly X509Store _rootStore, _myStore;
|
||||
private readonly IDictionary<string, X509Certificate2> _certificateCache;
|
||||
|
||||
public string Issuer { get; }
|
||||
public string CertificateAuthorityName { get; }
|
||||
|
||||
public DateTime NotAfter { get; set; }
|
||||
public DateTime NotBefore { get; set; }
|
||||
public int KeyLength { get; set; } = 1024;
|
||||
public bool IsCachingSignedCertificates { get; set; }
|
||||
|
||||
public X509Certificate2? Authority { get; private set; }
|
||||
|
||||
public Certifier()
|
||||
: this("Eavesdrop")
|
||||
{ }
|
||||
public Certifier(string issuer)
|
||||
: this(issuer, $"{issuer} Root Certificate Authority", StoreLocation.CurrentUser)
|
||||
{ }
|
||||
public Certifier(string issuer, string certificateAuthorityName)
|
||||
: this(issuer, certificateAuthorityName, StoreLocation.CurrentUser)
|
||||
{ }
|
||||
public Certifier(string issuer, string certificateAuthorityName, StoreLocation location)
|
||||
{
|
||||
_myStore = new X509Store(StoreName.My, location);
|
||||
_rootStore = new X509Store(StoreName.Root, location);
|
||||
_certificateCache = new Dictionary<string, X509Certificate2>();
|
||||
|
||||
NotBefore = DateTime.Now;
|
||||
NotAfter = NotBefore.AddMonths(1);
|
||||
|
||||
Issuer = issuer;
|
||||
CertificateAuthorityName = certificateAuthorityName;
|
||||
}
|
||||
|
||||
public bool CreateTrustedRootCertificate()
|
||||
{
|
||||
return (Authority = InstallCertificate(_rootStore, CertificateAuthorityName)) != null;
|
||||
}
|
||||
public bool DestroyTrustedRootCertificate()
|
||||
{
|
||||
return DestroyCertificates(_rootStore);
|
||||
}
|
||||
public bool ExportTrustedRootCertificate(string path)
|
||||
{
|
||||
X509Certificate2? rootCertificate = InstallCertificate(_rootStore, CertificateAuthorityName);
|
||||
|
||||
path = Path.GetFullPath(path);
|
||||
if (rootCertificate != null)
|
||||
{
|
||||
byte[] data = rootCertificate.Export(X509ContentType.Cert);
|
||||
File.WriteAllBytes(path, data);
|
||||
}
|
||||
return File.Exists(path);
|
||||
}
|
||||
|
||||
public X509Certificate2? GenerateCertificate(string certificateName)
|
||||
{
|
||||
return InstallCertificate(_myStore, certificateName);
|
||||
}
|
||||
public X509Certificate2 CreateCertificate(string subjectName, string alternateName)
|
||||
{
|
||||
using var rsa = RSA.Create(KeyLength);
|
||||
var certificateRequest = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
if (Authority == null)
|
||||
{
|
||||
certificateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(true, false, 0, true));
|
||||
certificateRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certificateRequest.PublicKey, false));
|
||||
|
||||
using X509Certificate2 certificate = certificateRequest.CreateSelfSigned(NotBefore.ToUniversalTime(), NotAfter.ToUniversalTime());
|
||||
|
||||
certificate.FriendlyName = alternateName;
|
||||
return new X509Certificate2(certificate.Export(X509ContentType.Pfx, string.Empty), string.Empty, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sanBuilder = new SubjectAlternativeNameBuilder();
|
||||
sanBuilder.AddDnsName(alternateName);
|
||||
|
||||
certificateRequest.CertificateExtensions.Add(sanBuilder.Build());
|
||||
certificateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
|
||||
certificateRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certificateRequest.PublicKey, false));
|
||||
|
||||
using X509Certificate2 certificate = certificateRequest.Create(Authority, Authority.NotBefore, Authority.NotAfter, Guid.NewGuid().ToByteArray());
|
||||
using X509Certificate2 certificateWithPrivateKey = certificate.CopyWithPrivateKey(rsa);
|
||||
|
||||
certificateWithPrivateKey.FriendlyName = alternateName;
|
||||
return new X509Certificate2(certificateWithPrivateKey.Export(X509ContentType.Pfx, string.Empty), string.Empty, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
|
||||
}
|
||||
}
|
||||
private X509Certificate2? InstallCertificate(X509Store store, string certificateName)
|
||||
{
|
||||
if (_certificateCache.TryGetValue(certificateName, out X509Certificate2? certificate))
|
||||
{
|
||||
if (DateTime.Now >= certificate.NotAfter)
|
||||
{
|
||||
_certificateCache.Remove(certificateName);
|
||||
}
|
||||
else return certificate;
|
||||
}
|
||||
lock (store)
|
||||
{
|
||||
try
|
||||
{
|
||||
store.Open(OpenFlags.ReadWrite);
|
||||
string subjectName = $"CN={certificateName}, O={Issuer}";
|
||||
|
||||
certificate = FindCertificates(store, subjectName)?[0];
|
||||
if (certificate != null && DateTime.Now >= certificate.NotAfter)
|
||||
{
|
||||
if (Authority == null)
|
||||
{
|
||||
DestroyCertificates();
|
||||
store.Open(OpenFlags.ReadWrite);
|
||||
}
|
||||
else
|
||||
{
|
||||
store.Remove(certificate);
|
||||
}
|
||||
certificate = null;
|
||||
}
|
||||
|
||||
if (certificate == null)
|
||||
{
|
||||
certificate = CreateCertificate(subjectName, certificateName);
|
||||
if (certificate != null)
|
||||
{
|
||||
if (store == _rootStore || IsCachingSignedCertificates)
|
||||
{
|
||||
store.Add(certificate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return certificate;
|
||||
}
|
||||
catch { return certificate = null; }
|
||||
finally
|
||||
{
|
||||
store.Close();
|
||||
if (certificate != null && !_certificateCache.ContainsKey(certificateName))
|
||||
{
|
||||
_certificateCache.Add(certificateName, certificate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool DestroyCertificates(X509Store store)
|
||||
{
|
||||
lock (store)
|
||||
{
|
||||
try
|
||||
{
|
||||
store.Open(OpenFlags.ReadWrite);
|
||||
X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByIssuerName, Issuer, false);
|
||||
|
||||
store.RemoveRange(certificates);
|
||||
IEnumerable<string> subjectNames = certificates.Cast<X509Certificate2>().Select(c => c.GetNameInfo(X509NameType.SimpleName, false));
|
||||
|
||||
foreach (string subjectName in subjectNames)
|
||||
{
|
||||
if (!_certificateCache.ContainsKey(subjectName)) continue;
|
||||
_certificateCache.Remove(subjectName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch { return false; }
|
||||
finally { store.Close(); }
|
||||
}
|
||||
}
|
||||
public bool DestroyCertificates() => DestroyCertificates(_myStore) && DestroyCertificates(_rootStore);
|
||||
|
||||
private static X509Certificate2Collection? FindCertificates(X509Store store, string subjectName)
|
||||
{
|
||||
X509Certificate2Collection certificates = store.Certificates
|
||||
.Find(X509FindType.FindBySubjectDistinguishedName, subjectName, false);
|
||||
|
||||
return certificates.Count > 0 ? certificates : null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_myStore.Close();
|
||||
_rootStore.Close();
|
||||
|
||||
_myStore.Dispose();
|
||||
_rootStore.Dispose();
|
||||
}
|
||||
}
|
200
Source/GrasscutterTools/Eavesdrop/Eavesdropper.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Eavesdrop.Network;
|
||||
|
||||
namespace Eavesdrop
|
||||
{
|
||||
public static class Eavesdropper
|
||||
{
|
||||
private static TcpListener _listener;
|
||||
private static readonly object _stateLock;
|
||||
|
||||
public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e);
|
||||
|
||||
public static event AsyncEventHandler<RequestInterceptedEventArgs> RequestInterceptedAsync;
|
||||
private static async Task OnRequestInterceptedAsync(RequestInterceptedEventArgs e)
|
||||
{
|
||||
Task interceptedTask = RequestInterceptedAsync?.Invoke(null, e);
|
||||
if (interceptedTask != null)
|
||||
{
|
||||
await interceptedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public static event AsyncEventHandler<ResponseInterceptedEventArgs> ResponseInterceptedAsync;
|
||||
private static async Task OnResponseInterceptedAsync(ResponseInterceptedEventArgs e)
|
||||
{
|
||||
Task interceptedTask = ResponseInterceptedAsync?.Invoke(null, e);
|
||||
if (interceptedTask != null)
|
||||
{
|
||||
await interceptedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<string> Overrides { get; }
|
||||
public static bool IsRunning { get; private set; }
|
||||
public static Certifier Certifier { get; set; }
|
||||
|
||||
static Eavesdropper()
|
||||
{
|
||||
_stateLock = new object();
|
||||
|
||||
ServicePointManager.Expect100Continue = true;
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
|
||||
|
||||
Overrides = new List<string>();
|
||||
Certifier = new Certifier("Eavesdrop", "Eavesdrop Root Certificate Authority");
|
||||
}
|
||||
|
||||
public static void Terminate()
|
||||
{
|
||||
lock (_stateLock)
|
||||
{
|
||||
ResetMachineProxy();
|
||||
IsRunning = false;
|
||||
|
||||
if (_listener != null)
|
||||
{
|
||||
_listener.Stop();
|
||||
_listener = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void Initiate(int port)
|
||||
{
|
||||
Initiate(port, Interceptors.Default);
|
||||
}
|
||||
public static void Initiate(int port, Interceptors interceptors)
|
||||
{
|
||||
Initiate(port, interceptors, true);
|
||||
}
|
||||
public static void Initiate(int port, Interceptors interceptors, bool setSystemProxy)
|
||||
{
|
||||
lock (_stateLock)
|
||||
{
|
||||
Terminate();
|
||||
|
||||
_listener = new TcpListener(IPAddress.Any, port);
|
||||
_listener.Start();
|
||||
|
||||
IsRunning = true;
|
||||
|
||||
Task.Factory.StartNew(InterceptRequestAsync, TaskCreationOptions.LongRunning);
|
||||
if (setSystemProxy)
|
||||
{
|
||||
SetMachineProxy(port, interceptors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task InterceptRequestAsync()
|
||||
{
|
||||
while (IsRunning && _listener != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
TcpClient client = await _listener.AcceptTcpClientAsync().ConfigureAwait(false);
|
||||
Task handleClientAsync = HandleClientAsync(client);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task HandleClientAsync(TcpClient client)
|
||||
{
|
||||
using var local = new EavesNode(Certifier, client);
|
||||
WebRequest request = await local.ReadRequestAsync().ConfigureAwait(false);
|
||||
if (request == null) return;
|
||||
|
||||
HttpContent requestContent = null;
|
||||
var requestArgs = new RequestInterceptedEventArgs(request);
|
||||
try
|
||||
{
|
||||
requestArgs.Content = requestContent = await local.ReadRequestContentAsync(request).ConfigureAwait(false);
|
||||
await OnRequestInterceptedAsync(requestArgs).ConfigureAwait(false);
|
||||
if (requestArgs.Cancel) return;
|
||||
|
||||
request = requestArgs.Request;
|
||||
if (requestArgs.Content != null)
|
||||
{
|
||||
await local.WriteRequestContentAsync(request, requestArgs.Content).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
requestContent?.Dispose();
|
||||
requestArgs.Content?.Dispose();
|
||||
}
|
||||
|
||||
WebResponse response = null;
|
||||
try { response = await request.GetResponseAsync().ConfigureAwait(false); }
|
||||
catch (WebException ex) { response = ex.Response; }
|
||||
catch (ProtocolViolationException)
|
||||
{
|
||||
response?.Dispose();
|
||||
response = null;
|
||||
}
|
||||
|
||||
if (response == null) return;
|
||||
HttpContent responseContent = null;
|
||||
var responseArgs = new ResponseInterceptedEventArgs(request, response);
|
||||
try
|
||||
{
|
||||
responseArgs.Content = responseContent = EavesNode.ReadResponseContent(response);
|
||||
await OnResponseInterceptedAsync(responseArgs).ConfigureAwait(false);
|
||||
if (responseArgs.Cancel) return;
|
||||
|
||||
await local.SendResponseAsync(responseArgs.Response, responseArgs.Content).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
response.Dispose();
|
||||
responseArgs.Response.Dispose();
|
||||
|
||||
responseContent?.Dispose();
|
||||
responseArgs.Content?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ResetMachineProxy()
|
||||
{
|
||||
INETOptions.Overrides.Clear();
|
||||
INETOptions.IsIgnoringLocalTraffic = false;
|
||||
|
||||
INETOptions.HTTPAddress = null;
|
||||
INETOptions.HTTPSAddress = null;
|
||||
INETOptions.IsProxyEnabled = false;
|
||||
|
||||
INETOptions.Save();
|
||||
}
|
||||
private static void SetMachineProxy(int port, Interceptors interceptors)
|
||||
{
|
||||
foreach (string @override in Overrides)
|
||||
{
|
||||
if (INETOptions.Overrides.Contains(@override)) continue;
|
||||
INETOptions.Overrides.Add(@override);
|
||||
}
|
||||
|
||||
string address = ("127.0.0.1:" + port);
|
||||
if (interceptors.HasFlag(Interceptors.HTTP))
|
||||
{
|
||||
INETOptions.HTTPAddress = address;
|
||||
}
|
||||
if (interceptors.HasFlag(Interceptors.HTTPS))
|
||||
{
|
||||
INETOptions.HTTPSAddress = address;
|
||||
}
|
||||
INETOptions.IsProxyEnabled = true;
|
||||
INETOptions.IsIgnoringLocalTraffic = true;
|
||||
|
||||
INETOptions.Save();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Eavesdrop
|
||||
{
|
||||
public class RequestInterceptedEventArgs : CancelEventArgs
|
||||
{
|
||||
private HttpWebRequest _httpRequest;
|
||||
|
||||
public HttpContent Content { get; set; }
|
||||
|
||||
private WebRequest _request;
|
||||
public WebRequest Request
|
||||
{
|
||||
get => _request;
|
||||
set
|
||||
{
|
||||
_request = value;
|
||||
_httpRequest = (value as HttpWebRequest);
|
||||
}
|
||||
}
|
||||
|
||||
public Uri Uri => Request?.RequestUri;
|
||||
public CookieContainer CookieContainer => _httpRequest?.CookieContainer;
|
||||
|
||||
public string Method
|
||||
{
|
||||
get => Request?.Method;
|
||||
set
|
||||
{
|
||||
if (Request != null)
|
||||
{
|
||||
Request.Method = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
public IWebProxy Proxy
|
||||
{
|
||||
get => Request?.Proxy;
|
||||
set
|
||||
{
|
||||
if (Request != null)
|
||||
{
|
||||
Request.Proxy = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
public string ContentType
|
||||
{
|
||||
get => Request?.ContentType;
|
||||
set
|
||||
{
|
||||
if (Request != null)
|
||||
{
|
||||
Request.ContentType = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
public WebHeaderCollection Headers
|
||||
{
|
||||
get => Request?.Headers;
|
||||
set
|
||||
{
|
||||
if (Request != null)
|
||||
{
|
||||
Request.Headers = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RequestInterceptedEventArgs(WebRequest request)
|
||||
{
|
||||
Request = request;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Eavesdrop.Network;
|
||||
|
||||
namespace Eavesdrop
|
||||
{
|
||||
public class ResponseInterceptedEventArgs : CancelEventArgs
|
||||
{
|
||||
private WebResponse _response;
|
||||
public WebResponse Response
|
||||
{
|
||||
get => _response;
|
||||
set
|
||||
{
|
||||
_response = value;
|
||||
if (value is HttpWebResponse httpResponse)
|
||||
{
|
||||
CookieContainer = new CookieContainer();
|
||||
CookieContainer.Add(httpResponse.Cookies);
|
||||
}
|
||||
else CookieContainer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public WebRequest Request { get; }
|
||||
public Uri Uri => Response?.ResponseUri;
|
||||
|
||||
public HttpContent Content { get; set; }
|
||||
public CookieContainer CookieContainer { get; private set; }
|
||||
|
||||
public string ContentType
|
||||
{
|
||||
get => Response?.ContentType;
|
||||
set
|
||||
{
|
||||
if (Response != null)
|
||||
{
|
||||
Response.ContentType = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
public WebHeaderCollection Headers
|
||||
{
|
||||
get => Response?.Headers;
|
||||
set
|
||||
{
|
||||
if (Response == null) return;
|
||||
foreach (string header in value.AllKeys)
|
||||
{
|
||||
Response.Headers[header] = value[header];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ResponseInterceptedEventArgs(WebRequest request, WebResponse response)
|
||||
{
|
||||
Request = request;
|
||||
Response = response;
|
||||
}
|
||||
}
|
||||
}
|
14
Source/GrasscutterTools/Eavesdrop/Interceptors.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Eavesdrop
|
||||
{
|
||||
[Flags]
|
||||
public enum Interceptors
|
||||
{
|
||||
None = 0,
|
||||
HTTP = 1,
|
||||
HTTPS = 2,
|
||||
|
||||
Default = (HTTP | HTTPS)
|
||||
}
|
||||
}
|
241
Source/GrasscutterTools/Eavesdrop/Internals/INETOptions.cs
Normal file
@@ -0,0 +1,241 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Eavesdrop
|
||||
{
|
||||
public static class INETOptions
|
||||
{
|
||||
private static readonly object _stateLock;
|
||||
private static readonly int _iNetOptionSize;
|
||||
private static readonly int _iNetPackageSize;
|
||||
private static readonly RegistryKey _proxyKey;
|
||||
|
||||
public static List<string> Overrides { get; }
|
||||
|
||||
public static string HTTPAddress { get; set; }
|
||||
public static string HTTPSAddress { get; set; }
|
||||
|
||||
public static bool IsProxyEnabled { get; set; }
|
||||
public static bool IsIgnoringLocalTraffic { get; set; }
|
||||
|
||||
static INETOptions()
|
||||
{
|
||||
_stateLock = new object();
|
||||
_iNetOptionSize = Marshal.SizeOf(typeof(INETOption));
|
||||
_iNetPackageSize = Marshal.SizeOf(typeof(INETPackage));
|
||||
_proxyKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true);
|
||||
|
||||
Overrides = new List<string>();
|
||||
Load();
|
||||
}
|
||||
|
||||
public static void Save()
|
||||
{
|
||||
lock (_stateLock)
|
||||
{
|
||||
var options = new List<INETOption>(3);
|
||||
string joinedAddresses = (IsProxyEnabled ? GetJoinedAddresses() : null);
|
||||
string joinedOverrides = (IsProxyEnabled ? GetJoinedOverrides() : null);
|
||||
|
||||
var kind = ProxyKind.PROXY_TYPE_DIRECT;
|
||||
if (!string.IsNullOrWhiteSpace(joinedAddresses))
|
||||
{
|
||||
options.Add(new INETOption(OptionKind.INTERNET_PER_CONN_PROXY_SERVER, joinedAddresses));
|
||||
if (!string.IsNullOrWhiteSpace(joinedOverrides))
|
||||
{
|
||||
options.Add(new INETOption(OptionKind.INTERNET_PER_CONN_PROXY_BYPASS, joinedOverrides));
|
||||
}
|
||||
kind |= ProxyKind.PROXY_TYPE_PROXY;
|
||||
}
|
||||
options.Insert(0, new INETOption(OptionKind.INTERNET_PER_CONN_FLAGS, (int)kind));
|
||||
|
||||
var inetPackage = new INETPackage
|
||||
{
|
||||
_optionError = 0,
|
||||
_size = _iNetPackageSize,
|
||||
_connection = IntPtr.Zero,
|
||||
_optionCount = options.Count
|
||||
};
|
||||
|
||||
IntPtr optionsPtr = Marshal.AllocCoTaskMem(_iNetOptionSize * options.Count);
|
||||
for (int i = 0; i < options.Count; ++i)
|
||||
{
|
||||
var optionPtr = new IntPtr((IntPtr.Size == 4 ? optionsPtr.ToInt32() : optionsPtr.ToInt64()) + (i * _iNetOptionSize));
|
||||
Marshal.StructureToPtr(options[i], optionPtr, false);
|
||||
}
|
||||
inetPackage._optionsPtr = optionsPtr;
|
||||
|
||||
IntPtr iNetPackagePtr = Marshal.AllocCoTaskMem(_iNetPackageSize);
|
||||
Marshal.StructureToPtr(inetPackage, iNetPackagePtr, false);
|
||||
|
||||
int returnvalue = (NativeMethods.InternetSetOption(IntPtr.Zero, 75, iNetPackagePtr, _iNetPackageSize) ? -1 : 0);
|
||||
if (returnvalue == 0)
|
||||
{
|
||||
returnvalue = Marshal.GetLastWin32Error();
|
||||
}
|
||||
|
||||
Marshal.FreeCoTaskMem(optionsPtr);
|
||||
Marshal.FreeCoTaskMem(iNetPackagePtr);
|
||||
if (returnvalue > 0)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
NativeMethods.InternetSetOption(IntPtr.Zero, 39, iNetPackagePtr, _iNetPackageSize);
|
||||
NativeMethods.InternetSetOption(IntPtr.Zero, 37, iNetPackagePtr, _iNetPackageSize);
|
||||
}
|
||||
}
|
||||
public static void Load()
|
||||
{
|
||||
lock (_stateLock)
|
||||
{
|
||||
LoadAddresses();
|
||||
LoadOverrides();
|
||||
IsProxyEnabled = (_proxyKey.GetValue("ProxyEnable")?.ToString() == "1");
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadOverrides()
|
||||
{
|
||||
string proxyOverride = _proxyKey.GetValue("ProxyOverride")?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(proxyOverride)) return;
|
||||
|
||||
string[] overrides = proxyOverride.Split(';');
|
||||
foreach (string @override in overrides)
|
||||
{
|
||||
if (@override == "<local>")
|
||||
{
|
||||
IsIgnoringLocalTraffic = true;
|
||||
}
|
||||
else if (!Overrides.Contains(@override))
|
||||
{
|
||||
Overrides.Add(@override);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void LoadAddresses()
|
||||
{
|
||||
string proxyServer = _proxyKey.GetValue("ProxyServer")?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(proxyServer)) return;
|
||||
|
||||
string[] values = proxyServer.Split(';');
|
||||
foreach (string value in values)
|
||||
{
|
||||
string[] pair = value.Split('=');
|
||||
if (pair.Length != 2)
|
||||
{
|
||||
HTTPAddress = value;
|
||||
HTTPSAddress = value;
|
||||
return;
|
||||
}
|
||||
|
||||
string address = pair[1];
|
||||
string protocol = pair[0];
|
||||
switch (protocol)
|
||||
{
|
||||
case "http": HTTPAddress = address; break;
|
||||
case "https": HTTPSAddress = address; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetJoinedAddresses()
|
||||
{
|
||||
var addresses = new List<string>(2);
|
||||
if (!string.IsNullOrWhiteSpace(HTTPAddress))
|
||||
{
|
||||
addresses.Add("http=" + HTTPAddress);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(HTTPSAddress))
|
||||
{
|
||||
addresses.Add("https=" + HTTPSAddress);
|
||||
}
|
||||
return string.Join(";", addresses);
|
||||
}
|
||||
private static string GetJoinedOverrides()
|
||||
{
|
||||
var overrides = new List<string>(Overrides);
|
||||
if (IsIgnoringLocalTraffic)
|
||||
{
|
||||
overrides.Add("<local>");
|
||||
}
|
||||
return string.Join(";", overrides);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
private struct INETOption
|
||||
{
|
||||
private readonly OptionKind _kind;
|
||||
private readonly INETOptionValue _value;
|
||||
|
||||
public INETOption(OptionKind kind, int value)
|
||||
{
|
||||
_kind = kind;
|
||||
_value = CreateValue(value);
|
||||
}
|
||||
public INETOption(OptionKind kind, string value)
|
||||
{
|
||||
_kind = kind;
|
||||
_value = CreateValue(value);
|
||||
}
|
||||
|
||||
private static INETOptionValue CreateValue(int value)
|
||||
{
|
||||
return new INETOptionValue
|
||||
{
|
||||
_intValue = value
|
||||
};
|
||||
}
|
||||
private static INETOptionValue CreateValue(string value)
|
||||
{
|
||||
return new INETOptionValue
|
||||
{
|
||||
_stringPointer = Marshal.StringToHGlobalAuto(value)
|
||||
};
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
private struct INETOptionValue
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int _intValue;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public IntPtr _stringPointer;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public System.Runtime.InteropServices.ComTypes.FILETIME _fileTime;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
private struct INETPackage
|
||||
{
|
||||
public int _size;
|
||||
public IntPtr _connection;
|
||||
public int _optionCount;
|
||||
public int _optionError;
|
||||
public IntPtr _optionsPtr;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum ProxyKind
|
||||
{
|
||||
PROXY_TYPE_DIRECT = 1,
|
||||
PROXY_TYPE_PROXY = 2,
|
||||
PROXY_TYPE_AUTO_PROXY_URL = 4,
|
||||
PROXY_TYPE_AUTO_DETECT = 8
|
||||
}
|
||||
private enum OptionKind
|
||||
{
|
||||
INTERNET_PER_CONN_FLAGS = 1,
|
||||
INTERNET_PER_CONN_PROXY_SERVER = 2,
|
||||
INTERNET_PER_CONN_PROXY_BYPASS = 3,
|
||||
INTERNET_PER_CONN_AUTOCONFIG_URL = 4
|
||||
}
|
||||
}
|
||||
}
|
12
Source/GrasscutterTools/Eavesdrop/Internals/NativeMethods.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Eavesdrop
|
||||
{
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
|
||||
}
|
||||
}
|
21
Source/GrasscutterTools/Eavesdrop/LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 ArachisH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
365
Source/GrasscutterTools/Eavesdrop/Network/EavesNode.cs
Normal file
@@ -0,0 +1,365 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.Security;
|
||||
using System.Globalization;
|
||||
using System.IO.Compression;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Authentication;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
//using BrotliSharpLib;
|
||||
|
||||
namespace Eavesdrop.Network
|
||||
{
|
||||
public class EavesNode : IDisposable
|
||||
{
|
||||
private SslStream _secureStream;
|
||||
private readonly TcpClient _client;
|
||||
private readonly Certifier _certifier;
|
||||
private static readonly Regex _responseCookieSplitter;
|
||||
|
||||
public bool IsSecure => (_secureStream != null);
|
||||
|
||||
static EavesNode()
|
||||
{
|
||||
_responseCookieSplitter = new Regex(",(?! )");
|
||||
}
|
||||
public EavesNode(Certifier certifier, TcpClient client)
|
||||
{
|
||||
_client = client;
|
||||
_certifier = certifier;
|
||||
|
||||
_client.NoDelay = true;
|
||||
}
|
||||
|
||||
public Task<HttpWebRequest> ReadRequestAsync()
|
||||
{
|
||||
return ReadRequestAsync(null);
|
||||
}
|
||||
private async Task<HttpWebRequest> ReadRequestAsync(Uri baseUri)
|
||||
{
|
||||
string method = null;
|
||||
var headers = new List<string>();
|
||||
string requestUrl = baseUri?.OriginalString;
|
||||
|
||||
string command = ReadNonBufferedLine();
|
||||
if (string.IsNullOrWhiteSpace(command)) return null;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(command)) return null;
|
||||
string[] values = command.Split(' ');
|
||||
|
||||
method = values[0];
|
||||
requestUrl += values[1];
|
||||
while (_client.Connected)
|
||||
{
|
||||
string header = ReadNonBufferedLine();
|
||||
if (string.IsNullOrWhiteSpace(header)) break;
|
||||
|
||||
headers.Add(header);
|
||||
}
|
||||
|
||||
if (method == "CONNECT")
|
||||
{
|
||||
baseUri = new Uri("https://" + requestUrl);
|
||||
await SendResponseAsync(HttpStatusCode.OK).ConfigureAwait(false);
|
||||
|
||||
if (!SecureTunnel(baseUri.Host)) return null;
|
||||
return await ReadRequestAsync(baseUri).ConfigureAwait(false);
|
||||
}
|
||||
else return CreateRequest(method, headers, new Uri(requestUrl));
|
||||
}
|
||||
|
||||
public async Task<ByteArrayContent> ReadRequestContentAsync(WebRequest request)
|
||||
{
|
||||
byte[] payload = await GetPayload(GetStream(), request.ContentLength).ConfigureAwait(false);
|
||||
if (payload == null) return null;
|
||||
|
||||
//if (request.Headers[HttpRequestHeader.ContentEncoding] == "br")
|
||||
//{
|
||||
// request.Headers[HttpRequestHeader.ContentEncoding] = ""; // No longer encoded.
|
||||
// payload = Brotli.DecompressBuffer(payload, 0, payload.Length);
|
||||
//}
|
||||
return new ByteArrayContent(payload);
|
||||
}
|
||||
public async Task WriteRequestContentAsync(WebRequest request, HttpContent content)
|
||||
{
|
||||
byte[] payload = null;
|
||||
if (content is StreamContent streamContent)
|
||||
{
|
||||
// TODO:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
else payload = await content.ReadAsByteArrayAsync().ConfigureAwait(false);
|
||||
|
||||
//if (request.Headers[HttpRequestHeader.ContentEncoding] == "br")
|
||||
//{
|
||||
// payload = Brotli.CompressBuffer(payload, 0, payload.Length);
|
||||
//}
|
||||
|
||||
request.ContentLength = payload.Length;
|
||||
using (Stream output = await request.GetRequestStreamAsync().ConfigureAwait(false))
|
||||
{
|
||||
await output.WriteAsync(payload, 0, payload.Length).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public Task SendResponseAsync(WebResponse response, HttpContent content)
|
||||
{
|
||||
string description = "OK";
|
||||
var status = HttpStatusCode.OK;
|
||||
if (response is HttpWebResponse httpResponse)
|
||||
{
|
||||
status = httpResponse.StatusCode;
|
||||
description = httpResponse.StatusDescription;
|
||||
}
|
||||
return SendResponseAsync(status, description, response.Headers, content);
|
||||
}
|
||||
public Task SendResponseAsync(HttpStatusCode status, string description = null)
|
||||
{
|
||||
return SendResponseAsync(status, (description ?? status.ToString()), null, null);
|
||||
}
|
||||
public async Task SendResponseAsync(HttpStatusCode status, string description, WebHeaderCollection headers, HttpContent content)
|
||||
{
|
||||
var headerBuilder = new StringBuilder();
|
||||
headerBuilder.AppendLine($"HTTP/{HttpVersion.Version10} {(int)status} {description}");
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (string header in headers.AllKeys)
|
||||
{
|
||||
if (header == "Transfer-Encoding") continue;
|
||||
|
||||
string value = headers[header];
|
||||
if (string.IsNullOrWhiteSpace(value)) continue;
|
||||
|
||||
if (header.Equals("Set-Cookie", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (string setCookie in _responseCookieSplitter.Split(value))
|
||||
{
|
||||
headerBuilder.AppendLine($"{header}: {setCookie}");
|
||||
}
|
||||
}
|
||||
else headerBuilder.AppendLine($"{header}: {value}");
|
||||
}
|
||||
}
|
||||
headerBuilder.AppendLine();
|
||||
|
||||
byte[] headerData = Encoding.UTF8.GetBytes(headerBuilder.ToString());
|
||||
await GetStream().WriteAsync(headerData, 0, headerData.Length).ConfigureAwait(false);
|
||||
if (content != null)
|
||||
{
|
||||
// TODO: If the Content-Encoding header has been changed, re-compress while writing?
|
||||
Stream input = await content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
|
||||
int bytesRead = 0;
|
||||
var buffer = new byte[8192];
|
||||
do
|
||||
{
|
||||
bytesRead = await input.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (_client.Connected && bytesRead > 0)
|
||||
{
|
||||
await GetStream().WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);
|
||||
}
|
||||
else return;
|
||||
}
|
||||
while (input.CanRead && _client.Connected);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetStream()
|
||||
{
|
||||
return ((Stream)_secureStream ?? _client.GetStream());
|
||||
}
|
||||
private StreamWriter WrapStreamWriter()
|
||||
{
|
||||
return new StreamWriter(GetStream(), Encoding.UTF8, 1024, true);
|
||||
}
|
||||
private StreamReader WrapStreamReader(int bufferSize = 1024)
|
||||
{
|
||||
return new StreamReader(GetStream(), Encoding.UTF8, true, bufferSize, true);
|
||||
}
|
||||
|
||||
private string ReadNonBufferedLine()
|
||||
{
|
||||
string line = string.Empty;
|
||||
try
|
||||
{
|
||||
using (var binaryInput = new BinaryReader(GetStream(), Encoding.UTF8, true))
|
||||
{
|
||||
do { line += binaryInput.ReadChar(); }
|
||||
while (!line.EndsWith("\r\n"));
|
||||
}
|
||||
}
|
||||
catch (EndOfStreamException) { line += "\r\n"; }
|
||||
return line.Substring(0, line.Length - 2);
|
||||
}
|
||||
private bool SecureTunnel(string host)
|
||||
{
|
||||
try
|
||||
{
|
||||
X509Certificate2 certificate = _certifier.GenerateCertificate(host);
|
||||
|
||||
_secureStream = new SslStream(GetStream());
|
||||
_secureStream.AuthenticateAsServer(certificate, false, SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
private IEnumerable<Cookie> GetCookies(string cookieHeader, string host)
|
||||
{
|
||||
foreach (string cookie in cookieHeader.Split(';'))
|
||||
{
|
||||
int nameEndIndex = cookie.IndexOf('=');
|
||||
if (nameEndIndex == -1) continue;
|
||||
|
||||
string name = cookie.Substring(0, nameEndIndex).Trim();
|
||||
string value = cookie.Substring(nameEndIndex + 1).Trim();
|
||||
|
||||
yield return new Cookie(name, value, "/", host);
|
||||
}
|
||||
}
|
||||
private HttpWebRequest CreateRequest(string method, List<string> headers, Uri requestUri)
|
||||
{
|
||||
HttpWebRequest request = WebRequest.CreateHttp(requestUri);
|
||||
request.ProtocolVersion = HttpVersion.Version10;
|
||||
request.CookieContainer = new CookieContainer();
|
||||
request.AllowAutoRedirect = false;
|
||||
request.KeepAlive = false;
|
||||
request.Method = method;
|
||||
request.Proxy = null;
|
||||
|
||||
foreach (string header in headers)
|
||||
{
|
||||
int delimiterIndex = header.IndexOf(':');
|
||||
if (delimiterIndex == -1) continue;
|
||||
|
||||
string name = header.Substring(0, delimiterIndex);
|
||||
string value = header.Substring(delimiterIndex + 2);
|
||||
switch (name.ToLower())
|
||||
{
|
||||
case "range":
|
||||
case "expect":
|
||||
case "keep-alive":
|
||||
case "connection":
|
||||
case "proxy-connection": break;
|
||||
|
||||
case "host": request.Host = value; break;
|
||||
case "accept": request.Accept = value; break;
|
||||
case "referer": request.Referer = value; break;
|
||||
case "user-agent": request.UserAgent = value; break;
|
||||
case "content-type": request.ContentType = value; break;
|
||||
|
||||
case "content-length":
|
||||
{
|
||||
request.ContentLength =
|
||||
long.Parse(value, CultureInfo.InvariantCulture);
|
||||
|
||||
break;
|
||||
}
|
||||
case "cookie":
|
||||
{
|
||||
foreach (Cookie cookie in GetCookies(value, request.Host))
|
||||
{
|
||||
try
|
||||
{
|
||||
request.CookieContainer.Add(cookie);
|
||||
}
|
||||
catch (CookieException) { }
|
||||
}
|
||||
request.Headers[name] = value;
|
||||
break;
|
||||
}
|
||||
case "if-modified-since":
|
||||
{
|
||||
request.IfModifiedSince = DateTime.Parse(
|
||||
value.Split(';')[0], CultureInfo.InvariantCulture);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "date":
|
||||
if (long.TryParse(value, out var timestamp))
|
||||
{
|
||||
request.Date = timestamp > 10_000_000_000L
|
||||
? DateTimeOffset.FromUnixTimeMilliseconds(timestamp).DateTime
|
||||
: DateTimeOffset.FromUnixTimeSeconds(timestamp).DateTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
request.Date = DateTime.Parse(value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
request.Headers[name] = value; break;
|
||||
}
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
GetStream().Dispose();
|
||||
_client.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static StreamContent ReadResponseContent(WebResponse response)
|
||||
{
|
||||
if (response.ContentLength == 0)
|
||||
{
|
||||
response.GetResponseStream().Dispose();
|
||||
return null;
|
||||
}
|
||||
|
||||
Stream input = response.GetResponseStream();
|
||||
//if (response is HttpWebResponse httpResponse && !string.IsNullOrWhiteSpace(httpResponse.ContentEncoding))
|
||||
//{
|
||||
// switch (httpResponse.ContentEncoding)
|
||||
// {
|
||||
// //case "br": input = new BrotliStream(input, CompressionMode.Decompress); break;
|
||||
// case "gzip": input = new GZipStream(input, CompressionMode.Decompress); break;
|
||||
// case "deflate": input = new DeflateStream(input, CompressionMode.Decompress); break;
|
||||
// }
|
||||
// response.Headers.Remove(HttpResponseHeader.ContentLength);
|
||||
// response.Headers.Remove(HttpResponseHeader.ContentEncoding);
|
||||
// response.Headers.Add(HttpResponseHeader.TransferEncoding, "chunked");
|
||||
//}
|
||||
return new StreamContent(input, response.ContentLength > 0 ? (int)response.ContentLength : 4096);
|
||||
}
|
||||
public static async Task<byte[]> GetPayload(Stream input, long length)
|
||||
{
|
||||
if (length < 1) return null;
|
||||
|
||||
int totalBytesRead = 0;
|
||||
int nullBytesReadCount = 0;
|
||||
var payload = new byte[length];
|
||||
do
|
||||
{
|
||||
int bytesLeft = (payload.Length - totalBytesRead);
|
||||
int bytesRead = await input.ReadAsync(payload, totalBytesRead, bytesLeft).ConfigureAwait(false);
|
||||
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
nullBytesReadCount = 0;
|
||||
totalBytesRead += bytesRead;
|
||||
}
|
||||
else if (++nullBytesReadCount >= 2) return null;
|
||||
}
|
||||
while (totalBytesRead != payload.Length);
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
}
|
@@ -56,7 +56,9 @@
|
||||
this.LblCountLabel = new System.Windows.Forms.Label();
|
||||
this.ListItems = new System.Windows.Forms.ListBox();
|
||||
this.GrpMonsterList = new System.Windows.Forms.GroupBox();
|
||||
this.LblClearMonsterFilter = new System.Windows.Forms.Label();
|
||||
this.GrpItemList = new System.Windows.Forms.GroupBox();
|
||||
this.LblClearItemFilter = new System.Windows.Forms.Label();
|
||||
this.GrpDropList.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUDMaxWeight)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUDMinWeight)).BeginInit();
|
||||
@@ -292,19 +294,37 @@
|
||||
// GrpMonsterList
|
||||
//
|
||||
resources.ApplyResources(this.GrpMonsterList, "GrpMonsterList");
|
||||
this.GrpMonsterList.Controls.Add(this.LblClearMonsterFilter);
|
||||
this.GrpMonsterList.Controls.Add(this.ListMonsters);
|
||||
this.GrpMonsterList.Controls.Add(this.TxtMonsterFilter);
|
||||
this.GrpMonsterList.Name = "GrpMonsterList";
|
||||
this.GrpMonsterList.TabStop = false;
|
||||
//
|
||||
// LblClearMonsterFilter
|
||||
//
|
||||
resources.ApplyResources(this.LblClearMonsterFilter, "LblClearMonsterFilter");
|
||||
this.LblClearMonsterFilter.BackColor = System.Drawing.Color.White;
|
||||
this.LblClearMonsterFilter.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.LblClearMonsterFilter.Name = "LblClearMonsterFilter";
|
||||
this.LblClearMonsterFilter.Click += new System.EventHandler(this.LblClearMonsterFilter_Click);
|
||||
//
|
||||
// GrpItemList
|
||||
//
|
||||
resources.ApplyResources(this.GrpItemList, "GrpItemList");
|
||||
this.GrpItemList.Controls.Add(this.LblClearItemFilter);
|
||||
this.GrpItemList.Controls.Add(this.TxtItemFilter);
|
||||
this.GrpItemList.Controls.Add(this.ListItems);
|
||||
this.GrpItemList.Name = "GrpItemList";
|
||||
this.GrpItemList.TabStop = false;
|
||||
//
|
||||
// LblClearItemFilter
|
||||
//
|
||||
resources.ApplyResources(this.LblClearItemFilter, "LblClearItemFilter");
|
||||
this.LblClearItemFilter.BackColor = System.Drawing.Color.White;
|
||||
this.LblClearItemFilter.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.LblClearItemFilter.Name = "LblClearItemFilter";
|
||||
this.LblClearItemFilter.Click += new System.EventHandler(this.LblClearItemFilter_Click);
|
||||
//
|
||||
// FormDropEditor
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
@@ -362,5 +382,7 @@
|
||||
private System.Windows.Forms.Button BtnPaste;
|
||||
private System.Windows.Forms.Button BtnClear;
|
||||
private System.Windows.Forms.Button BtnCopyAll;
|
||||
private System.Windows.Forms.Label LblClearMonsterFilter;
|
||||
private System.Windows.Forms.Label LblClearItemFilter;
|
||||
}
|
||||
}
|
@@ -199,6 +199,15 @@ namespace GrasscutterTools.Forms
|
||||
private void TxtMonsterFilter_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
UIUtil.ListBoxFilter(ListMonsters, Monsters, TxtMonsterFilter.Text);
|
||||
LblClearMonsterFilter.Visible = TxtMonsterFilter.Text.Length > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击清空怪物过滤器标签时触发
|
||||
/// </summary>
|
||||
private void LblClearMonsterFilter_Click(object sender, EventArgs e)
|
||||
{
|
||||
TxtMonsterFilter.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -496,6 +505,15 @@ namespace GrasscutterTools.Forms
|
||||
private void TxtItemFilter_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
UIUtil.ListBoxFilter(ListItems, GameData.Items.Lines, TxtItemFilter.Text);
|
||||
LblClearItemFilter.Visible = TxtItemFilter.Text.Length > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击清空物品列表过滤器标签时触发
|
||||
/// </summary>
|
||||
private void LblClearItemFilter_Click(object sender, EventArgs e)
|
||||
{
|
||||
TxtItemFilter.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -507,5 +525,7 @@ namespace GrasscutterTools.Forms
|
||||
}
|
||||
|
||||
#endregion - 物品列表 -
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -241,7 +241,7 @@
|
||||
<value>GrpMonsterList</value>
|
||||
</data>
|
||||
<data name=">>ListMonsters.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="TxtMonsterFilter.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Left, Right</value>
|
||||
@@ -265,7 +265,7 @@
|
||||
<value>GrpMonsterList</value>
|
||||
</data>
|
||||
<data name=">>TxtMonsterFilter.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="TxtItemFilter.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Left, Right</value>
|
||||
@@ -289,7 +289,7 @@
|
||||
<value>GrpItemList</value>
|
||||
</data>
|
||||
<data name=">>TxtItemFilter.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="ListDropData.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
@@ -802,11 +802,47 @@
|
||||
<value>GrpItemList</value>
|
||||
</data>
|
||||
<data name=">>ListItems.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="GrpMonsterList.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left</value>
|
||||
</data>
|
||||
<data name="LblClearMonsterFilter.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name="LblClearMonsterFilter.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="LblClearMonsterFilter.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="LblClearMonsterFilter.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>228, 25</value>
|
||||
</data>
|
||||
<data name="LblClearMonsterFilter.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>16, 17</value>
|
||||
</data>
|
||||
<data name="LblClearMonsterFilter.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>23</value>
|
||||
</data>
|
||||
<data name="LblClearMonsterFilter.Text" xml:space="preserve">
|
||||
<value>X</value>
|
||||
</data>
|
||||
<data name="LblClearMonsterFilter.Visible" type="System.Boolean, mscorlib">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name=">>LblClearMonsterFilter.Name" xml:space="preserve">
|
||||
<value>LblClearMonsterFilter</value>
|
||||
</data>
|
||||
<data name=">>LblClearMonsterFilter.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>LblClearMonsterFilter.Parent" xml:space="preserve">
|
||||
<value>GrpMonsterList</value>
|
||||
</data>
|
||||
<data name=">>LblClearMonsterFilter.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="GrpMonsterList.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>12, 41</value>
|
||||
</data>
|
||||
@@ -834,6 +870,42 @@
|
||||
<data name="GrpItemList.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Right</value>
|
||||
</data>
|
||||
<data name="LblClearItemFilter.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name="LblClearItemFilter.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="LblClearItemFilter.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="LblClearItemFilter.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>227, 25</value>
|
||||
</data>
|
||||
<data name="LblClearItemFilter.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>16, 17</value>
|
||||
</data>
|
||||
<data name="LblClearItemFilter.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>23</value>
|
||||
</data>
|
||||
<data name="LblClearItemFilter.Text" xml:space="preserve">
|
||||
<value>X</value>
|
||||
</data>
|
||||
<data name="LblClearItemFilter.Visible" type="System.Boolean, mscorlib">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name=">>LblClearItemFilter.Name" xml:space="preserve">
|
||||
<value>LblClearItemFilter</value>
|
||||
</data>
|
||||
<data name=">>LblClearItemFilter.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>LblClearItemFilter.Parent" xml:space="preserve">
|
||||
<value>GrpItemList</value>
|
||||
</data>
|
||||
<data name=">>LblClearItemFilter.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="GrpItemList.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>576, 41</value>
|
||||
</data>
|
||||
|
@@ -50,8 +50,10 @@ namespace GrasscutterTools.Forms
|
||||
|
||||
private void InitBannerPrefab()
|
||||
{
|
||||
CmbPrefab.Items.Clear();
|
||||
CmbPrefab.Items.AddRange(GameData.GachaBannerPrefabs.Names);
|
||||
CmbPrefab.DisplayMember = "Value";
|
||||
CmbPrefab.DataSource = GameData.GachaBannerPrefabs;
|
||||
//CmbPrefab.Items.Clear();
|
||||
//CmbPrefab.Items.AddRange(GameData.GachaBannerPrefabs.Names);
|
||||
}
|
||||
|
||||
private void InitCheckedListBoxs()
|
||||
@@ -96,6 +98,11 @@ namespace GrasscutterTools.Forms
|
||||
|
||||
#region - UI -
|
||||
|
||||
private static string TrimPrefixAndSuffix(string text, int prefixLength, int suffixLength)
|
||||
{
|
||||
return text.Substring(prefixLength, text.Length - prefixLength - suffixLength);
|
||||
}
|
||||
|
||||
private void ShowBanner(GachaBanner banner)
|
||||
{
|
||||
try
|
||||
@@ -103,10 +110,17 @@ namespace GrasscutterTools.Forms
|
||||
NUDGachaType.Value = banner.GachaType;
|
||||
NUDScheduleId.Value = banner.ScheduleId;
|
||||
CmbBannerType.SelectedIndex = (int)banner.BannerType;
|
||||
if (string.IsNullOrEmpty(banner.TitlePath) || !int.TryParse(banner.TitlePath.Substring("UI_GACHA_SHOW_PANEL_A".Length, 3), out int prefabId))
|
||||
const string titlePrefix = "UI_GACHA_SHOW_PANEL_";
|
||||
const string suffix = "_TITLE";
|
||||
if (string.IsNullOrEmpty(banner.TitlePath) || banner.TitlePath.Length <= titlePrefix.Length + suffix.Length)
|
||||
{
|
||||
CmbPrefab.SelectedIndex = -1;
|
||||
}
|
||||
else
|
||||
CmbPrefab.SelectedIndex = Array.IndexOf(GameData.GachaBannerPrefabs.Ids, prefabId);
|
||||
{
|
||||
var titleKey = TrimPrefixAndSuffix(banner.TitlePath, titlePrefix.Length, suffix.Length);
|
||||
CmbPrefab.SelectedIndex = GameData.GachaBannerTitles.FindIndex(it => it.Key == titleKey);
|
||||
}
|
||||
RbCostItem224.Checked = banner.CostItem == 224;
|
||||
RbCostItem223.Checked = banner.CostItem == 223;
|
||||
NUDBeginTime.Value = banner.BeginTime;
|
||||
@@ -153,15 +167,15 @@ namespace GrasscutterTools.Forms
|
||||
else
|
||||
purpleIds = TxtRateUpItems2.Text.Split(',').Select(s => int.Parse(s.Trim())).ToArray();
|
||||
|
||||
var prefabId = GameData.GachaBannerPrefabs.Ids[CmbPrefab.SelectedIndex];
|
||||
var prefabId = GameData.GachaBannerPrefabs[CmbPrefab.SelectedIndex].Key;
|
||||
GachaBanner banner = new GachaBanner
|
||||
{
|
||||
GachaType = (int)NUDGachaType.Value,
|
||||
ScheduleId = (int)NUDScheduleId.Value,
|
||||
BannerType = (BannerType)CmbBannerType.SelectedIndex,
|
||||
PrefabPath = $"GachaShowPanel_A{prefabId:000}",
|
||||
PreviewPrefabPath = $"UI_Tab_GachaShowPanel_A{prefabId:000}",
|
||||
TitlePath = $"UI_GACHA_SHOW_PANEL_A{prefabId:000}_TITLE",
|
||||
PrefabPath = $"GachaShowPanel_{prefabId}",
|
||||
PreviewPrefabPath = $"UI_Tab_GachaShowPanel_{prefabId}",
|
||||
TitlePath = $"UI_GACHA_SHOW_PANEL_{prefabId}_TITLE",
|
||||
CostItem = RbCostItem224.Checked ? 224 : 223,
|
||||
BeginTime = (int)NUDBeginTime.Value,
|
||||
EndTime = (int)NUDEndTime.Value,
|
||||
|
@@ -50,8 +50,11 @@ namespace GrasscutterTools.Forms
|
||||
|
||||
private void InitBannerPrefab()
|
||||
{
|
||||
CmbPrefab.Items.Clear();
|
||||
CmbPrefab.Items.AddRange(GameData.GachaBannerPrefabs.Names);
|
||||
CmbPrefab.DisplayMember = "Value";
|
||||
CmbPrefab.DataSource = GameData.GachaBannerPrefabs;
|
||||
|
||||
//CmbPrefab.Items.Clear();
|
||||
//CmbPrefab.Items.AddRange(GameData.GachaBannerPrefabs.Names);
|
||||
}
|
||||
|
||||
private void LnkWeightHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
@@ -206,6 +209,10 @@ namespace GrasscutterTools.Forms
|
||||
|
||||
#region - 序列化 -
|
||||
|
||||
private static string TrimPrefixAndSuffix(string text, int prefixLength, int suffixLength)
|
||||
{
|
||||
return text.Substring(prefixLength, text.Length - prefixLength - suffixLength);
|
||||
}
|
||||
private void ShowBanner(GachaBanner2 banner)
|
||||
{
|
||||
try
|
||||
@@ -213,10 +220,17 @@ namespace GrasscutterTools.Forms
|
||||
NUDGachaType.Value = banner.GachaType;
|
||||
NUDScheduleId.Value = banner.ScheduleId;
|
||||
CmbBannerType.SelectedIndex = (int)banner.BannerType;
|
||||
if (string.IsNullOrEmpty(banner.TitlePath) || !int.TryParse(banner.TitlePath.Substring("UI_GACHA_SHOW_PANEL_A".Length, 3), out int prefabId))
|
||||
const string titlePrefix = "UI_GACHA_SHOW_PANEL_";
|
||||
const string suffix = "_TITLE";
|
||||
if (string.IsNullOrEmpty(banner.TitlePath) || banner.TitlePath.Length <= titlePrefix.Length + suffix.Length)
|
||||
{
|
||||
CmbPrefab.SelectedIndex = -1;
|
||||
}
|
||||
else
|
||||
CmbPrefab.SelectedIndex = Array.IndexOf(GameData.GachaBannerPrefabs.Ids, prefabId);
|
||||
{
|
||||
var titleKey = TrimPrefixAndSuffix(banner.TitlePath, titlePrefix.Length, suffix.Length);
|
||||
CmbPrefab.SelectedIndex = GameData.GachaBannerTitles.FindIndex(it => it.Key == titleKey);
|
||||
}
|
||||
RbCostItem224.Checked = banner.CostItem == 224;
|
||||
RbCostItem223.Checked = banner.CostItem == 223;
|
||||
DTPBeginTime.Value = DateTimeOffset.FromUnixTimeSeconds(banner.BeginTime).DateTime;
|
||||
@@ -248,16 +262,16 @@ namespace GrasscutterTools.Forms
|
||||
MessageBox.Show("请选择奖池预制", Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return null;
|
||||
}
|
||||
|
||||
var prefabId = GameData.GachaBannerPrefabs.Ids[CmbPrefab.SelectedIndex];
|
||||
|
||||
var prefabId = GameData.GachaBannerPrefabs[CmbPrefab.SelectedIndex].Key;
|
||||
var banner = new GachaBanner2
|
||||
{
|
||||
GachaType = (int)NUDGachaType.Value,
|
||||
ScheduleId = (int)NUDScheduleId.Value,
|
||||
BannerType = (BannerType)CmbBannerType.SelectedIndex,
|
||||
PrefabPath = $"GachaShowPanel_A{prefabId:000}",
|
||||
PreviewPrefabPath = $"UI_Tab_GachaShowPanel_A{prefabId:000}",
|
||||
TitlePath = $"UI_GACHA_SHOW_PANEL_A{prefabId:000}_TITLE",
|
||||
PrefabPath = $"GachaShowPanel_{prefabId}",
|
||||
PreviewPrefabPath = $"UI_Tab_GachaShowPanel_{prefabId}",
|
||||
TitlePath = $"UI_GACHA_SHOW_PANEL_{prefabId}_TITLE",
|
||||
CostItem = RbCostItem224.Checked ? 224 : 223,
|
||||
BeginTime = (int)new DateTimeOffset(DTPBeginTime.Value, TimeSpan.Zero).ToUnixTimeSeconds(),
|
||||
EndTime = (int)new DateTimeOffset(DTPEndTime.Value, TimeSpan.Zero).ToUnixTimeSeconds(),
|
||||
|
@@ -61,10 +61,10 @@ namespace GrasscutterTools.Forms
|
||||
|
||||
private void InitBannerPrefab()
|
||||
{
|
||||
CmbPrefab.Items.Clear();
|
||||
CmbPrefab.Items.AddRange(GameData.GachaBannerPrefabs.Names);
|
||||
CmbTitlePath.Items.Clear();
|
||||
CmbTitlePath.Items.AddRange(GameData.GachaBannerTitles.Names);
|
||||
CmbPrefab.DisplayMember = "Value";
|
||||
CmbPrefab.DataSource = GameData.GachaBannerPrefabs;
|
||||
CmbTitlePath.DisplayMember = "Value";
|
||||
CmbTitlePath.DataSource = GameData.GachaBannerTitles;
|
||||
}
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
@@ -405,6 +405,12 @@ namespace GrasscutterTools.Forms
|
||||
|
||||
#region - 卡池参数 -
|
||||
|
||||
private static string TrimPrefixAndSuffix(string text, int prefixLength, int suffixLength)
|
||||
{
|
||||
return text.Substring(prefixLength, text.Length - prefixLength - suffixLength);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 显示指定卡池参数
|
||||
/// </summary>
|
||||
@@ -416,14 +422,28 @@ namespace GrasscutterTools.Forms
|
||||
NUDGachaType.Value = banner.GachaType;
|
||||
NUDScheduleId.Value = banner.ScheduleId;
|
||||
CmbBannerType.SelectedIndex = (int)banner.BannerType;
|
||||
if (string.IsNullOrEmpty(banner.PrefabPath) || !int.TryParse(banner.PrefabPath.Substring("GachaShowPanel_A".Length, 3), out int prefabId))
|
||||
const string prefabPrefix = "GachaShowPanel_";
|
||||
if (string.IsNullOrEmpty(banner.PrefabPath) || banner.PrefabPath.Length <= prefabPrefix.Length)
|
||||
{
|
||||
CmbPrefab.SelectedIndex = -1;
|
||||
}
|
||||
else
|
||||
CmbPrefab.SelectedIndex = Array.IndexOf(GameData.GachaBannerPrefabs.Ids, prefabId);
|
||||
if (string.IsNullOrEmpty(banner.TitlePath) || !int.TryParse(banner.TitlePath.Substring("UI_GACHA_SHOW_PANEL_A".Length, 3), out int titleId))
|
||||
{
|
||||
var prefabKey = banner.PrefabPath.Substring(prefabPrefix.Length);
|
||||
CmbPrefab.SelectedIndex = GameData.GachaBannerPrefabs.FindIndex(it => it.Key == prefabKey);
|
||||
}
|
||||
|
||||
const string titlePrefix = "UI_GACHA_SHOW_PANEL_";
|
||||
const string suffix = "_TITLE";
|
||||
if (string.IsNullOrEmpty(banner.TitlePath) || banner.TitlePath.Length <= titlePrefix.Length + suffix.Length)
|
||||
{
|
||||
CmbTitlePath.SelectedIndex = -1;
|
||||
}
|
||||
else
|
||||
CmbTitlePath.SelectedIndex = Array.IndexOf(GameData.GachaBannerTitles.Ids, titleId);
|
||||
{
|
||||
var titleKey = TrimPrefixAndSuffix(banner.TitlePath, titlePrefix.Length, suffix.Length);
|
||||
CmbTitlePath.SelectedIndex = GameData.GachaBannerTitles.FindIndex(it => it.Key == titleKey);
|
||||
}
|
||||
RbCostItem224.Checked = banner.CostItemId == 224;
|
||||
RbCostItem223.Checked = banner.CostItemId == 223;
|
||||
NUDCostItemAmount1.Value = banner.CoseItemAmount;
|
||||
@@ -458,16 +478,16 @@ namespace GrasscutterTools.Forms
|
||||
return null;
|
||||
}
|
||||
|
||||
var prefabId = GameData.GachaBannerPrefabs.Ids[CmbPrefab.SelectedIndex];
|
||||
var titleId = GameData.GachaBannerTitles.Ids[CmbTitlePath.SelectedIndex];
|
||||
var prefabId = GameData.GachaBannerPrefabs[CmbPrefab.SelectedIndex].Key;
|
||||
var titleId = GameData.GachaBannerTitles[CmbTitlePath.SelectedIndex].Key;
|
||||
var banner = new GachaBanner3
|
||||
{
|
||||
GachaType = (int)NUDGachaType.Value,
|
||||
ScheduleId = (int)NUDScheduleId.Value,
|
||||
BannerType = (BannerType)CmbBannerType.SelectedIndex,
|
||||
PrefabPath = $"GachaShowPanel_A{prefabId:000}",
|
||||
PreviewPrefabPath = $"UI_Tab_GachaShowPanel_A{prefabId:000}",
|
||||
TitlePath = $"UI_GACHA_SHOW_PANEL_A{titleId:000}_TITLE",
|
||||
PrefabPath = $"GachaShowPanel_{prefabId}",
|
||||
PreviewPrefabPath = $"UI_Tab_GachaShowPanel_{prefabId}",
|
||||
TitlePath = $"UI_GACHA_SHOW_PANEL_{titleId}_TITLE",
|
||||
CostItemId = RbCostItem224.Checked ? 224 : 223,
|
||||
CoseItemAmount = (int)NUDCostItemAmount1.Value,
|
||||
CostItemId10 = RbCostItem224.Checked ? 224 : 223,
|
||||
|
30
Source/GrasscutterTools/Forms/FormMain.Designer.cs
generated
@@ -32,16 +32,15 @@ namespace GrasscutterTools.Forms
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain));
|
||||
this.NavContainer = new System.Windows.Forms.SplitContainer();
|
||||
this.ListPages = new System.Windows.Forms.ListBox();
|
||||
this.TCMain = new System.Windows.Forms.TabControl();
|
||||
this.CmbCommand = new System.Windows.Forms.ComboBox();
|
||||
this.BtnCopy = new System.Windows.Forms.Button();
|
||||
this.ChkAutoCopy = new System.Windows.Forms.CheckBox();
|
||||
this.GrpCommand = new System.Windows.Forms.GroupBox();
|
||||
this.LblClearFilter = new System.Windows.Forms.Label();
|
||||
this.BtnInvokeOpenCommand = new System.Windows.Forms.Button();
|
||||
this.MenuSpawnEntityFilter = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
((System.ComponentModel.ISupportInitialize)(this.NavContainer)).BeginInit();
|
||||
this.NavContainer.Panel1.SuspendLayout();
|
||||
this.NavContainer.Panel2.SuspendLayout();
|
||||
this.NavContainer.SuspendLayout();
|
||||
this.GrpCommand.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
@@ -55,10 +54,6 @@ namespace GrasscutterTools.Forms
|
||||
//
|
||||
this.NavContainer.Panel1.Controls.Add(this.ListPages);
|
||||
//
|
||||
// NavContainer.Panel2
|
||||
//
|
||||
this.NavContainer.Panel2.Controls.Add(this.TCMain);
|
||||
//
|
||||
// ListPages
|
||||
//
|
||||
this.ListPages.BackColor = System.Drawing.Color.WhiteSmoke;
|
||||
@@ -68,23 +63,17 @@ namespace GrasscutterTools.Forms
|
||||
this.ListPages.FormattingEnabled = true;
|
||||
this.ListPages.Name = "ListPages";
|
||||
this.ListPages.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.ListPages_DrawItem);
|
||||
this.ListPages.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.ListPages_MeasureItem);
|
||||
this.ListPages.SelectedIndexChanged += new System.EventHandler(this.ListPages_SelectedIndexChanged);
|
||||
this.ListPages.SizeChanged += new System.EventHandler(this.ListPages_SizeChanged);
|
||||
//
|
||||
// TCMain
|
||||
//
|
||||
resources.ApplyResources(this.TCMain, "TCMain");
|
||||
this.TCMain.Multiline = true;
|
||||
this.TCMain.Name = "TCMain";
|
||||
this.TCMain.SelectedIndex = 0;
|
||||
this.TCMain.SizeMode = System.Windows.Forms.TabSizeMode.Fixed;
|
||||
//
|
||||
// CmbCommand
|
||||
//
|
||||
resources.ApplyResources(this.CmbCommand, "CmbCommand");
|
||||
this.CmbCommand.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
|
||||
this.CmbCommand.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
|
||||
this.CmbCommand.Name = "CmbCommand";
|
||||
this.CmbCommand.TextChanged += new System.EventHandler(this.CmbCommand_TextChanged);
|
||||
this.CmbCommand.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TxtCommand_KeyDown);
|
||||
//
|
||||
// BtnCopy
|
||||
@@ -103,6 +92,7 @@ namespace GrasscutterTools.Forms
|
||||
// GrpCommand
|
||||
//
|
||||
resources.ApplyResources(this.GrpCommand, "GrpCommand");
|
||||
this.GrpCommand.Controls.Add(this.LblClearFilter);
|
||||
this.GrpCommand.Controls.Add(this.BtnInvokeOpenCommand);
|
||||
this.GrpCommand.Controls.Add(this.BtnCopy);
|
||||
this.GrpCommand.Controls.Add(this.ChkAutoCopy);
|
||||
@@ -110,6 +100,14 @@ namespace GrasscutterTools.Forms
|
||||
this.GrpCommand.Name = "GrpCommand";
|
||||
this.GrpCommand.TabStop = false;
|
||||
//
|
||||
// LblClearFilter
|
||||
//
|
||||
resources.ApplyResources(this.LblClearFilter, "LblClearFilter");
|
||||
this.LblClearFilter.BackColor = System.Drawing.Color.White;
|
||||
this.LblClearFilter.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.LblClearFilter.Name = "LblClearFilter";
|
||||
this.LblClearFilter.Click += new System.EventHandler(this.LblClearFilter_Click);
|
||||
//
|
||||
// BtnInvokeOpenCommand
|
||||
//
|
||||
resources.ApplyResources(this.BtnInvokeOpenCommand, "BtnInvokeOpenCommand");
|
||||
@@ -119,6 +117,7 @@ namespace GrasscutterTools.Forms
|
||||
//
|
||||
// MenuSpawnEntityFilter
|
||||
//
|
||||
this.MenuSpawnEntityFilter.ImageScalingSize = new System.Drawing.Size(24, 24);
|
||||
this.MenuSpawnEntityFilter.Name = "MenuSpawnEntityFilter";
|
||||
resources.ApplyResources(this.MenuSpawnEntityFilter, "MenuSpawnEntityFilter");
|
||||
//
|
||||
@@ -134,7 +133,6 @@ namespace GrasscutterTools.Forms
|
||||
this.Load += new System.EventHandler(this.FormMain_Load);
|
||||
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.FormMain_KeyDown);
|
||||
this.NavContainer.Panel1.ResumeLayout(false);
|
||||
this.NavContainer.Panel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.NavContainer)).EndInit();
|
||||
this.NavContainer.ResumeLayout(false);
|
||||
this.GrpCommand.ResumeLayout(false);
|
||||
@@ -150,9 +148,9 @@ namespace GrasscutterTools.Forms
|
||||
private System.Windows.Forms.CheckBox ChkAutoCopy;
|
||||
private System.Windows.Forms.GroupBox GrpCommand;
|
||||
private System.Windows.Forms.Button BtnInvokeOpenCommand;
|
||||
private System.Windows.Forms.TabControl TCMain;
|
||||
private System.Windows.Forms.ContextMenuStrip MenuSpawnEntityFilter;
|
||||
private System.Windows.Forms.ListBox ListPages;
|
||||
private System.Windows.Forms.SplitContainer NavContainer;
|
||||
private System.Windows.Forms.Label LblClearFilter;
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,8 @@
|
||||
**/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -30,15 +32,20 @@ using GrasscutterTools.Utils;
|
||||
|
||||
namespace GrasscutterTools.Forms
|
||||
{
|
||||
public partial class FormMain : Form
|
||||
internal partial class FormMain : Form
|
||||
{
|
||||
#region - 初始化 Init -
|
||||
private const string TAG = nameof(FormMain);
|
||||
|
||||
private const string TAG = "FormMain";
|
||||
public static FormMain Instance { get; private set; }
|
||||
|
||||
#region - 初始化 Init -
|
||||
|
||||
public FormMain()
|
||||
{
|
||||
Logger.I(TAG, "FormMain ctor enter");
|
||||
|
||||
Instance = this;
|
||||
|
||||
InitializeComponent();
|
||||
Icon = Resources.IconGrasscutter;
|
||||
|
||||
@@ -85,6 +92,13 @@ namespace GrasscutterTools.Forms
|
||||
Logger.I(TAG, "Restore NavContainer SplitterDistance: " + NavContainer.SplitterDistance);
|
||||
}
|
||||
|
||||
// 还原窗口的不透明度
|
||||
if (Settings.Default.WindowOpacity < 100)
|
||||
{
|
||||
Opacity = Settings.Default.WindowOpacity / 100.0;
|
||||
Logger.I(TAG, "Restore window opacity: " + Opacity);
|
||||
}
|
||||
|
||||
// 恢复自动复制选项状态
|
||||
ChkAutoCopy.Checked = Settings.Default.AutoCopy;
|
||||
|
||||
@@ -99,133 +113,13 @@ namespace GrasscutterTools.Forms
|
||||
Logger.I(TAG, "FormMain ctor completed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化并创建所有页面
|
||||
/// </summary>
|
||||
private void InitPages()
|
||||
{
|
||||
Logger.I(TAG, "InitPages enter");
|
||||
TCMain.SuspendLayout();
|
||||
var ph = CreatePage<PageHome>();
|
||||
ph.OnLanguageChanged = () => FormMain_Load(this, EventArgs.Empty);
|
||||
var poc = CreatePage<PageOpenCommand>();
|
||||
poc.ShowTipInRunButton = msg => ShowTip(msg, BtnInvokeOpenCommand);
|
||||
var pcc = CreatePage<PageCustomCommands>();
|
||||
var phk = CreatePage<PageHotKey>();
|
||||
pcc.OnAddHotKey = tag =>
|
||||
{
|
||||
phk.AddNewHotKey(tag);
|
||||
// 跳转到快捷键界面
|
||||
for (var i = 0; i < TCMain.Controls.Count; i++)
|
||||
{
|
||||
if (TCMain.Controls[i].Controls[0] == phk)
|
||||
{
|
||||
ListPages.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
CreatePage<PageGiveArtifact>();
|
||||
CreatePage<PageSpawn>();
|
||||
CreatePage<PageGiveItem>();
|
||||
CreatePage<PageAvatar>();
|
||||
CreatePage<PageGiveWeapon>();
|
||||
CreatePage<PageManagement>();
|
||||
CreatePage<PageMail>();
|
||||
CreatePage<PageTasks>();
|
||||
CreatePage<PageQuest>();
|
||||
CreatePage<PageScene>();
|
||||
CreatePage<PageAchievement>();
|
||||
CreatePage<PageSetProp>();
|
||||
CreatePage<PageAbout>();
|
||||
#if DEBUG
|
||||
CreatePage<PageTools>();
|
||||
#endif
|
||||
TCMain.ResumeLayout();
|
||||
Logger.I(TAG, "InitPages completed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化页面导航
|
||||
/// 重载界面
|
||||
/// </summary>
|
||||
private void InitPagesNav()
|
||||
public void Reload()
|
||||
{
|
||||
ListPages.Items.Clear();
|
||||
ListPages.Items.AddRange(new object[]
|
||||
{
|
||||
Resources.PageHomeTitle,
|
||||
Resources.PageOpenCommandTitle,
|
||||
Resources.PageCustomCommandsTitle,
|
||||
Resources.PageHotKey,
|
||||
Resources.PageGetArtifactTitle,
|
||||
Resources.PageSpawnTitle,
|
||||
Resources.PageGiveItemTitle,
|
||||
Resources.PageAvatarTitle,
|
||||
Resources.PageGiveWeaponTitle,
|
||||
Resources.PageManagementTitle,
|
||||
Resources.PageMailTitle,
|
||||
Resources.PageTasksTitle,
|
||||
Resources.PageQuestTitle,
|
||||
Resources.PageSceneTitle,
|
||||
Resources.PageAchievementTitle,
|
||||
Resources.PageSetPropTitle,
|
||||
Resources.PageAboutTitle,
|
||||
#if DEBUG
|
||||
"Tools",
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导航列表项居中绘制
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void ListPages_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
e.DrawBackground();
|
||||
e.DrawFocusRectangle();
|
||||
var strFmt = new StringFormat
|
||||
{
|
||||
Alignment = StringAlignment.Center, //文本垂直居中
|
||||
LineAlignment = StringAlignment.Center //文本水平居中
|
||||
};
|
||||
e.Graphics.DrawString(ListPages.Items[e.Index].ToString(), e.Font, new SolidBrush(e.ForeColor), e.Bounds, strFmt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导航列表大小改变时触发
|
||||
/// </summary>
|
||||
private void ListPages_SizeChanged(object sender, EventArgs e)
|
||||
{
|
||||
// 立刻重绘列表项
|
||||
ListPages.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建指定类型页面
|
||||
/// </summary>
|
||||
/// <typeparam name="T">页面类型,必须继承BasePage</typeparam>
|
||||
/// <returns>页面实例</returns>
|
||||
private T CreatePage<T>() where T : BasePage, new()
|
||||
{
|
||||
var page = new T
|
||||
{
|
||||
SetCommand = SetCommand,
|
||||
RunCommands = RunCommands,
|
||||
GetCommand = () => CmbCommand.Text,
|
||||
Dock = DockStyle.Fill,
|
||||
Name = typeof(T).Name,
|
||||
};
|
||||
var tp = new TabPage();
|
||||
TCMain.TabPages.Add(tp);
|
||||
tp.Controls.Add(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
private void ListPages_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
TCMain.SelectedIndex = ListPages.SelectedIndex;
|
||||
FormMain_Load(this, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -241,21 +135,23 @@ namespace GrasscutterTools.Forms
|
||||
if (DesignMode) return;
|
||||
|
||||
// 加载页面导航
|
||||
InitPagesNav();
|
||||
UpdatePagesNav();
|
||||
|
||||
// 加载游戏ID资源
|
||||
GameData.LoadResources();
|
||||
|
||||
// 遍历每一个页面重新加载
|
||||
foreach (TabPage tp in TCMain.Controls)
|
||||
foreach (var page in Pages.Values)
|
||||
{
|
||||
if (tp.Controls.Count > 0 && tp.Controls[0] is BasePage page)
|
||||
{
|
||||
Logger.I(TAG, $"{page.Name} OnLoad enter");
|
||||
page.OnLoad();
|
||||
Logger.I(TAG, $"{page.Name} OnLoad completed");
|
||||
}
|
||||
Logger.I(TAG, $"{page.Name} OnLoad enter");
|
||||
page.OnLoad();
|
||||
Logger.I(TAG, $"{page.Name} OnLoad completed");
|
||||
}
|
||||
|
||||
// 默认选中首页
|
||||
if (ListPages.SelectedIndex == -1)
|
||||
ListPages.SelectedIndex = 0;
|
||||
|
||||
Logger.I(TAG, "FormMain_Load completed");
|
||||
}
|
||||
|
||||
@@ -266,10 +162,11 @@ namespace GrasscutterTools.Forms
|
||||
{
|
||||
Logger.I(TAG, "FormMain FormClosed enter");
|
||||
// 遍历每一个页面,通知关闭
|
||||
foreach (TabPage tp in TCMain.Controls)
|
||||
foreach (var page in Pages.Values)
|
||||
{
|
||||
if (tp.Controls.Count > 0 && tp.Controls[0] is BasePage page)
|
||||
page.OnClosed();
|
||||
Logger.I(TAG, $"{page.Name} OnClosed enter");
|
||||
page.OnClosed();
|
||||
Logger.I(TAG, $"{page.Name} OnClosed completed");
|
||||
}
|
||||
|
||||
// 保存当前设置
|
||||
@@ -305,6 +202,254 @@ namespace GrasscutterTools.Forms
|
||||
|
||||
#endregion - 初始化 Init -
|
||||
|
||||
#region - 页面导航 Nav -
|
||||
|
||||
public Dictionary<string, BasePage> Pages { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化并创建所有页面
|
||||
/// </summary>
|
||||
private void InitPages()
|
||||
{
|
||||
Logger.I(TAG, "InitPages enter");
|
||||
Pages = new Dictionary<string, BasePage>(32);
|
||||
CreatePage<PageHome>();
|
||||
var poc = CreatePage<PageOpenCommand>();
|
||||
poc.ShowTipInRunButton = msg => ShowTip(msg, BtnInvokeOpenCommand);
|
||||
CreatePage<PageProxy>();
|
||||
CreatePage<PageCustomCommands>();
|
||||
CreatePage<PageHotKey>();
|
||||
CreatePage<PageGiveArtifact>();
|
||||
CreatePage<PageSetProp>();
|
||||
CreatePage<PageSpawn>();
|
||||
CreatePage<PageGiveItem>();
|
||||
CreatePage<PageAvatar>();
|
||||
CreatePage<PageGiveWeapon>();
|
||||
CreatePage<PageScene>();
|
||||
CreatePage<PageSceneTag>();
|
||||
CreatePage<PageWeather>();
|
||||
CreatePage<PageTasks>();
|
||||
CreatePage<PageManagement>();
|
||||
CreatePage<PageMail>();
|
||||
CreatePage<PageQuest>();
|
||||
CreatePage<PageAchievement>();
|
||||
CreatePage<PageSettings>();
|
||||
CreatePage<PageAbout>();
|
||||
#if DEBUG
|
||||
CreatePage<PageTools>();
|
||||
#endif
|
||||
Logger.I(TAG, "InitPages completed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前的页面选项卡顺序
|
||||
/// string Item1 = Page Name(Key)
|
||||
/// bool Item2 = IsVisible
|
||||
/// </summary>
|
||||
public List<Tuple<string, bool>> PageTabOrders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 加载页面选项卡顺序
|
||||
/// </summary>
|
||||
private List<Tuple<string, bool>> LoadPageTabOrders()
|
||||
{
|
||||
if (PageTabOrders != null) return PageTabOrders;
|
||||
List<Tuple<string, bool>> tabOrders;
|
||||
if (!(Settings.Default.PageOrders?.Count > 0))
|
||||
{
|
||||
tabOrders = new List<Tuple<string, bool>>(Pages.Count);
|
||||
// 默认状态
|
||||
foreach (var tab in Pages)
|
||||
tabOrders.Add(new Tuple<string, bool>(tab.Key, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
tabOrders = new List<Tuple<string, bool>>(Settings.Default.PageOrders.Count);
|
||||
// 从设置中读取
|
||||
foreach (var item in Settings.Default.PageOrders)
|
||||
{
|
||||
// 冒号分隔的项 "PageHome:1" 0=隐藏 1=显示
|
||||
var sp = item.IndexOf(':');
|
||||
if (sp == -1 || !int.TryParse(item.Substring(sp + 1), out var isVisible)) continue;
|
||||
tabOrders.Add(new Tuple<string, bool>(item.Substring(0, sp), isVisible != 0));
|
||||
}
|
||||
}
|
||||
|
||||
return tabOrders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置页面选项卡顺序
|
||||
/// </summary>
|
||||
public void ResetPageTabOrders()
|
||||
{
|
||||
PageTabOrders = new List<Tuple<string, bool>>(Pages.Count);
|
||||
// 默认状态
|
||||
foreach (var tab in Pages)
|
||||
PageTabOrders.Add(new Tuple<string, bool>(tab.Key, true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存页面选项卡顺序
|
||||
/// </summary>
|
||||
public void SavePageTabOrders()
|
||||
{
|
||||
if (PageTabOrders == null || PageTabOrders.Count == 0)
|
||||
{
|
||||
Settings.Default.PageOrders = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var setting = new StringCollection();
|
||||
// 冒号分隔的项 "PageHome:1" 0=隐藏 1=显示
|
||||
foreach (var pageOrder in PageTabOrders)
|
||||
setting.Add($"{pageOrder.Item1}:{(pageOrder.Item2?'1':'0')}");
|
||||
Settings.Default.PageOrders = setting;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化页面导航
|
||||
/// </summary>
|
||||
public void UpdatePagesNav()
|
||||
{
|
||||
ListPages.BeginUpdate();
|
||||
ListPages.Items.Clear();
|
||||
|
||||
// 以下代码主要是为了加载用户自定义顺序的选项卡
|
||||
var tabOrders = LoadPageTabOrders();
|
||||
// 程序更新后增加或减少了界面的情况
|
||||
if (tabOrders.Count != Pages.Count)
|
||||
{
|
||||
PageTabOrders = new List<Tuple<string, bool>>(Pages.Count);
|
||||
var i = 0;
|
||||
var pageKeys = Pages.Keys.ToList();
|
||||
foreach (var pageOrder in tabOrders)
|
||||
{
|
||||
// 新增页面优先显示
|
||||
if (i < pageKeys.Count && tabOrders.All(it => it.Item1 != pageKeys[i]))
|
||||
{
|
||||
PageTabOrders.Add(new Tuple<string, bool>(pageKeys[i], true));
|
||||
ListPages.Items.Add(Pages[pageKeys[i]].Text);
|
||||
}
|
||||
// 尝试获取页面标题
|
||||
if (Pages.TryGetValue(pageOrder.Item1, out var page))
|
||||
{
|
||||
// 仅设置为可见时添加
|
||||
if (pageOrder.Item2)
|
||||
ListPages.Items.Add(page.Text);
|
||||
PageTabOrders.Add(new Tuple<string, bool>(pageOrder.Item1, pageOrder.Item2));
|
||||
}
|
||||
// 如果获取不到页面标题,说明在本次更新中这个页面被删掉了,因此设置项也随之更新
|
||||
i++;
|
||||
}
|
||||
// 加上新增在最后的页面
|
||||
if (ListPages.Items.Count == i)
|
||||
{
|
||||
while (i < Pages.Count)
|
||||
{
|
||||
PageTabOrders.Add(new Tuple<string, bool>(pageKeys[i], true));
|
||||
ListPages.Items.Add(Pages[pageKeys[i]].Text);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// 保存页面顺序
|
||||
SavePageTabOrders();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 按照设定顺序显示
|
||||
foreach (var pageOrder in tabOrders)
|
||||
{
|
||||
if (pageOrder.Item2)
|
||||
ListPages.Items.Add(Pages[pageOrder.Item1].Text);
|
||||
}
|
||||
|
||||
PageTabOrders = tabOrders;
|
||||
}
|
||||
|
||||
ListPages.EndUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导航列表选中项改变时触发
|
||||
/// </summary>
|
||||
private void ListPages_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (ListPages.SelectedIndex == -1) return;
|
||||
// 根据选中索引反查选中页面Key
|
||||
var key = PageTabOrders.Where(it => it.Item2)
|
||||
.ElementAt(ListPages.SelectedIndex)
|
||||
.Item1;
|
||||
// 通过Key找到页面的父节点也就是TabPage,设置为选中项
|
||||
ShowPage(Pages[key]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 展示页面
|
||||
/// </summary>
|
||||
/// <param name="page">页面实例</param>
|
||||
private void ShowPage(BasePage page)
|
||||
{
|
||||
NavContainer.Panel2.SuspendLayout();
|
||||
NavContainer.Panel2.Controls.Clear();
|
||||
NavContainer.Panel2.Controls.Add(page);
|
||||
NavContainer.Panel2.ResumeLayout();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导航列表项居中绘制
|
||||
/// </summary>
|
||||
private void ListPages_DrawItem(object sender, DrawItemEventArgs e)
|
||||
{
|
||||
e.DrawBackground();
|
||||
e.DrawFocusRectangle();
|
||||
var strFmt = new StringFormat
|
||||
{
|
||||
Alignment = StringAlignment.Center, //文本垂直居中
|
||||
LineAlignment = StringAlignment.Center //文本水平居中
|
||||
};
|
||||
e.Graphics.DrawString(ListPages.Items[e.Index].ToString(), e.Font, new SolidBrush(e.ForeColor), e.Bounds, strFmt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导航列表高度测量
|
||||
/// </summary>
|
||||
private void ListPages_MeasureItem(object sender, MeasureItemEventArgs e)
|
||||
{
|
||||
// 列表项高度为字体高度1.5倍
|
||||
e.ItemHeight = ListPages.Font.Height * 3 / 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导航列表大小改变时触发
|
||||
/// </summary>
|
||||
private void ListPages_SizeChanged(object sender, EventArgs e)
|
||||
{
|
||||
// 立刻重绘列表项
|
||||
ListPages.Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建指定类型页面
|
||||
/// </summary>
|
||||
/// <typeparam name="T">页面类型,必须继承BasePage</typeparam>
|
||||
/// <returns>页面实例</returns>
|
||||
private T CreatePage<T>() where T : BasePage, new()
|
||||
{
|
||||
var page = new T
|
||||
{
|
||||
SetCommand = SetCommand,
|
||||
RunCommands = RunCommands,
|
||||
GetCommand = () => CmbCommand.Text,
|
||||
Dock = DockStyle.Fill,
|
||||
Name = typeof(T).Name,
|
||||
};
|
||||
Pages.Add(page.Name, page);
|
||||
return page;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region - 快捷键执行 HotKey -
|
||||
|
||||
/// <summary>
|
||||
@@ -380,10 +525,12 @@ namespace GrasscutterTools.Forms
|
||||
/// <param name="args">参数</param>
|
||||
private void SetCommand(string command, string args)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(args))
|
||||
command = $"{command} {args}";
|
||||
command = command.Trim();
|
||||
if (Settings.Default.IsIncludeUID)
|
||||
SetCommand($"{command} @{Settings.Default.Uid} {args.Trim()}");
|
||||
else
|
||||
SetCommand($"{command} {args.Trim()}");
|
||||
command = $"{command} @{Settings.Default.Uid}";
|
||||
SetCommand(command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -443,7 +590,7 @@ namespace GrasscutterTools.Forms
|
||||
/// <returns>是否执行成功</returns>
|
||||
private async Task<bool> RunRawCommands(string commands)
|
||||
{
|
||||
if (commands.IndexOf('|') == -1)
|
||||
if (commands.IndexOf('|') == -1 || Common.OC?.CanInvokeMultipleCmd == true)
|
||||
return await RunCommands(FormatCommand(commands));
|
||||
return await RunCommands(commands.Split('|').Select(FormatCommand).ToArray());
|
||||
}
|
||||
@@ -469,16 +616,7 @@ namespace GrasscutterTools.Forms
|
||||
if (Common.OC == null || !Common.OC.CanInvoke)
|
||||
{
|
||||
ShowTip(Resources.RequireOpenCommandTip, BtnInvokeOpenCommand);
|
||||
//TCMain.SelectedTab = TPRemoteCall;
|
||||
for (var i = 0; i < TCMain.Controls.Count; i++)
|
||||
{
|
||||
if (TCMain.Controls[i].Controls[0] is PageOpenCommand)
|
||||
{
|
||||
ListPages.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NavigateTo<PageOpenCommand>();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -500,7 +638,7 @@ namespace GrasscutterTools.Forms
|
||||
{
|
||||
Logger.I(TAG, "RunCommand:" + cmd);
|
||||
var msg = await Common.OC.Invoke(cmd);
|
||||
TxtCommandRunLog.AppendText(string.IsNullOrEmpty(msg) ? "OK" : msg);
|
||||
TxtCommandRunLog.AppendText(string.IsNullOrEmpty(msg) ? "OK" : msg.Replace("\n", "\r\n"));
|
||||
TxtCommandRunLog.AppendText(Environment.NewLine);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -557,8 +695,8 @@ namespace GrasscutterTools.Forms
|
||||
Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom,
|
||||
Multiline = true,
|
||||
Font = new Font("Consolas", 9F),
|
||||
Location = new Point(BtnInvokeOpenCommand.Left, BtnInvokeOpenCommand.Bottom + 6),
|
||||
Size = new Size(GrpCommand.Width - BtnInvokeOpenCommand.Left * 2, TxtCommandRunLogMinHeight),
|
||||
Location = new Point(ChkAutoCopy.Left, ChkAutoCopy.Bottom + 6),
|
||||
Size = new Size(GrpCommand.Width - ChkAutoCopy.Left * 2, TxtCommandRunLogMinHeight),
|
||||
ReadOnly = true,
|
||||
BackColor = Color.White,
|
||||
ScrollBars = ScrollBars.Vertical,
|
||||
@@ -581,13 +719,42 @@ namespace GrasscutterTools.Forms
|
||||
// F5 为执行命令
|
||||
OnOpenCommandInvoke();
|
||||
}
|
||||
else if (e.Alt && e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9)
|
||||
else if ((e.Alt || e.Control) && e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9)
|
||||
{
|
||||
// Alt+数字键 = 跳转到对应页面
|
||||
// Alt|Ctrl+数字键 = 跳转到对应页面
|
||||
var i = e.KeyCode == Keys.D0 ? 9 : e.KeyCode - Keys.D1;
|
||||
if (i < ListPages.Items.Count)
|
||||
ListPages.SelectedIndex = i;
|
||||
}
|
||||
else if (e.Control && e.KeyCode == Keys.Tab)
|
||||
{
|
||||
// 切换到下一个页面
|
||||
ListPages.SelectedIndex = (ListPages.SelectedIndex + 1) % ListPages.Items.Count;
|
||||
}
|
||||
else if (Common.KeyGo.IsEnabled == false)
|
||||
{
|
||||
foreach (var hotkeyItem in Common.KeyGo.Items)
|
||||
{
|
||||
if (!hotkeyItem.IsEnabled) continue;
|
||||
|
||||
var t = hotkeyItem.HotKey.LastIndexOf('+');
|
||||
var key = (t >= 0) ? hotkeyItem.HotKey.Substring(t+1) : hotkeyItem.HotKey;
|
||||
if (e.KeyCode != (Keys)Enum.Parse(typeof(Keys), key.Trim()))
|
||||
continue;
|
||||
|
||||
if (t >= 0)
|
||||
{
|
||||
if (hotkeyItem.HotKey.Contains("Ctrl") && !e.Control)
|
||||
continue;
|
||||
if (hotkeyItem.HotKey.Contains("Shift") && !e.Shift)
|
||||
continue;
|
||||
if (hotkeyItem.HotKey.Contains("Alt") && !e.Alt)
|
||||
continue;
|
||||
}
|
||||
BeginInvoke(new Func<Task>(() => RunRawCommands(hotkeyItem.Commands)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -610,6 +777,46 @@ namespace GrasscutterTools.Forms
|
||||
TTip.Show(message, control, 0, control.Size.Height, 3000);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导航到目标页面并返回该页面实例
|
||||
/// </summary>
|
||||
/// <typeparam name="TPage">页面类型</typeparam>
|
||||
public TPage NavigateTo<TPage>() where TPage : BasePage
|
||||
{
|
||||
var key = typeof(TPage).Name;
|
||||
var page = Pages[key] as TPage;
|
||||
var i = 0;
|
||||
foreach (var it in PageTabOrders.Where(it => it.Item2))
|
||||
{
|
||||
if (it.Item1 == key)
|
||||
{
|
||||
ListPages.SelectedIndex = i;
|
||||
return page;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
ShowPage(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
#endregion - 通用 General -
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 命令栏文本改变时触发
|
||||
/// </summary>
|
||||
private void CmbCommand_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
LblClearFilter.Visible = CmbCommand.Text.Length > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击清空命令栏标签时触发
|
||||
/// </summary>
|
||||
private void LblClearFilter_Click(object sender, EventArgs e)
|
||||
{
|
||||
CmbCommand.Text = "";
|
||||
}
|
||||
}
|
||||
}
|
@@ -135,6 +135,6 @@
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="$this.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>Inherit</value>
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
</root>
|
@@ -133,7 +133,7 @@
|
||||
</data>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="ListPages.ItemHeight" type="System.Int32, mscorlib">
|
||||
<value>22</value>
|
||||
<value>25</value>
|
||||
</data>
|
||||
<data name="ListPages.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>0, 0</value>
|
||||
@@ -171,39 +171,6 @@
|
||||
<data name="NavContainer.Panel1MinSize" type="System.Int32, mscorlib">
|
||||
<value>80</value>
|
||||
</data>
|
||||
<data name="TCMain.Appearance" type="System.Windows.Forms.TabAppearance, System.Windows.Forms">
|
||||
<value>FlatButtons</value>
|
||||
</data>
|
||||
<data name="TCMain.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
|
||||
<value>Fill</value>
|
||||
</data>
|
||||
<data name="TCMain.ItemSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>0, 1</value>
|
||||
</data>
|
||||
<data name="TCMain.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>0, 0</value>
|
||||
</data>
|
||||
<data name="TCMain.MinimumSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>610, 275</value>
|
||||
</data>
|
||||
<data name="TCMain.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>656, 275</value>
|
||||
</data>
|
||||
<data name="TCMain.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name=">>TCMain.Name" xml:space="preserve">
|
||||
<value>TCMain</value>
|
||||
</data>
|
||||
<data name=">>TCMain.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>TCMain.Parent" xml:space="preserve">
|
||||
<value>NavContainer.Panel2</value>
|
||||
</data>
|
||||
<data name=">>TCMain.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>NavContainer.Panel2.Name" xml:space="preserve">
|
||||
<value>NavContainer.Panel2</value>
|
||||
</data>
|
||||
@@ -244,7 +211,7 @@
|
||||
<value>Top, Left, Right</value>
|
||||
</data>
|
||||
<data name="CmbCommand.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>87, 21</value>
|
||||
<value>115, 22</value>
|
||||
</data>
|
||||
<data name="CmbCommand.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>600, 25</value>
|
||||
@@ -262,19 +229,16 @@
|
||||
<value>GrpCommand</value>
|
||||
</data>
|
||||
<data name=">>CmbCommand.ZOrder" xml:space="preserve">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="BtnCopy.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name="BtnCopy.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="BtnCopy.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>693, 22</value>
|
||||
<value>59, 22</value>
|
||||
</data>
|
||||
<data name="BtnCopy.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>50, 23</value>
|
||||
<value>50, 25</value>
|
||||
</data>
|
||||
<data name="BtnCopy.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
@@ -292,10 +256,7 @@
|
||||
<value>GrpCommand</value>
|
||||
</data>
|
||||
<data name=">>BtnCopy.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="ChkAutoCopy.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="ChkAutoCopy.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
@@ -304,7 +265,7 @@
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="ChkAutoCopy.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>749, 24</value>
|
||||
<value>10, 24</value>
|
||||
</data>
|
||||
<data name="ChkAutoCopy.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>51, 21</value>
|
||||
@@ -325,19 +286,58 @@
|
||||
<value>GrpCommand</value>
|
||||
</data>
|
||||
<data name=">>ChkAutoCopy.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="GrpCommand.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>680, 26</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>16, 17</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>24</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Text" xml:space="preserve">
|
||||
<value>X</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Visible" type="System.Boolean, mscorlib">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.Name" xml:space="preserve">
|
||||
<value>LblClearFilter</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.Parent" xml:space="preserve">
|
||||
<value>GrpCommand</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="BtnInvokeOpenCommand.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name="BtnInvokeOpenCommand.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="BtnInvokeOpenCommand.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>6, 22</value>
|
||||
<value>721, 22</value>
|
||||
</data>
|
||||
<data name="BtnInvokeOpenCommand.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>75, 23</value>
|
||||
<value>75, 25</value>
|
||||
</data>
|
||||
<data name="BtnInvokeOpenCommand.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>0</value>
|
||||
@@ -355,7 +355,7 @@
|
||||
<value>GrpCommand</value>
|
||||
</data>
|
||||
<data name=">>BtnInvokeOpenCommand.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="GrpCommand.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>12, 293</value>
|
||||
|
@@ -119,22 +119,22 @@
|
||||
</resheader>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="CmbCommand.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>132, 21</value>
|
||||
<value>155, 21</value>
|
||||
</data>
|
||||
<data name="CmbCommand.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>513, 25</value>
|
||||
<value>523, 25</value>
|
||||
</data>
|
||||
<data name="BtnCopy.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>651, 21</value>
|
||||
<value>57, 21</value>
|
||||
</data>
|
||||
<data name="BtnCopy.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>92, 23</value>
|
||||
<value>92, 25</value>
|
||||
</data>
|
||||
<data name="BtnCopy.Text" xml:space="preserve">
|
||||
<value>Копировать</value>
|
||||
</data>
|
||||
<data name="ChkAutoCopy.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>749, 23</value>
|
||||
<value>6, 24</value>
|
||||
</data>
|
||||
<data name="ChkAutoCopy.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>55, 21</value>
|
||||
@@ -145,14 +145,17 @@
|
||||
<data name="GrpCommand.Text" xml:space="preserve">
|
||||
<value>Команды - [Ctrl] Запуск и замена - [Shift] Добавить - [Alt] Только запустить - [|] Разделитель</value>
|
||||
</data>
|
||||
<data name="BtnInvokeOpenCommand.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>684, 21</value>
|
||||
</data>
|
||||
<data name="BtnInvokeOpenCommand.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>120, 23</value>
|
||||
<value>120, 25</value>
|
||||
</data>
|
||||
<data name="BtnInvokeOpenCommand.Text" xml:space="preserve">
|
||||
<value>Выполнить (F5)</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="$this.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>Inherit</value>
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
</root>
|
@@ -131,6 +131,6 @@
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="$this.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>Inherit</value>
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
</root>
|
@@ -37,6 +37,7 @@
|
||||
this.BtnClearGoods = new System.Windows.Forms.Button();
|
||||
this.BtnDeleteGoods = new System.Windows.Forms.Button();
|
||||
this.GrpItems = new System.Windows.Forms.GroupBox();
|
||||
this.LblClearItemFilter = new System.Windows.Forms.Label();
|
||||
this.TxtItemFilter = new System.Windows.Forms.TextBox();
|
||||
this.GrpGoodsInfo = new System.Windows.Forms.GroupBox();
|
||||
this.BtnSaveGoods = new System.Windows.Forms.Button();
|
||||
@@ -132,8 +133,8 @@
|
||||
//
|
||||
// GrpShopList
|
||||
//
|
||||
resources.ApplyResources(this.GrpShopList, "GrpShopList");
|
||||
this.GrpShopList.Controls.Add(this.ListShop);
|
||||
resources.ApplyResources(this.GrpShopList, "GrpShopList");
|
||||
this.GrpShopList.Name = "GrpShopList";
|
||||
this.GrpShopList.TabStop = false;
|
||||
//
|
||||
@@ -163,11 +164,20 @@
|
||||
// GrpItems
|
||||
//
|
||||
resources.ApplyResources(this.GrpItems, "GrpItems");
|
||||
this.GrpItems.Controls.Add(this.LblClearItemFilter);
|
||||
this.GrpItems.Controls.Add(this.TxtItemFilter);
|
||||
this.GrpItems.Controls.Add(this.ListItems);
|
||||
this.GrpItems.Name = "GrpItems";
|
||||
this.GrpItems.TabStop = false;
|
||||
//
|
||||
// LblClearItemFilter
|
||||
//
|
||||
resources.ApplyResources(this.LblClearItemFilter, "LblClearItemFilter");
|
||||
this.LblClearItemFilter.BackColor = System.Drawing.Color.White;
|
||||
this.LblClearItemFilter.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.LblClearItemFilter.Name = "LblClearItemFilter";
|
||||
this.LblClearItemFilter.Click += new System.EventHandler(this.LblClearItemFilter_Click);
|
||||
//
|
||||
// TxtItemFilter
|
||||
//
|
||||
resources.ApplyResources(this.TxtItemFilter, "TxtItemFilter");
|
||||
@@ -698,5 +708,6 @@
|
||||
private System.Windows.Forms.TextBox TxtItemFilter;
|
||||
private System.Windows.Forms.Button BtnClearGoods;
|
||||
private System.Windows.Forms.Button BtnDeleteGoods;
|
||||
private System.Windows.Forms.Label LblClearItemFilter;
|
||||
}
|
||||
}
|
@@ -529,6 +529,15 @@ namespace GrasscutterTools.Forms
|
||||
private void TxtItemFilter_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
UIUtil.ListBoxFilter(ListItems, GameData.Items.Lines, TxtItemFilter.Text);
|
||||
LblClearItemFilter.Visible = TxtItemFilter.Text.Length > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击清空物品列表过滤器标签时触发
|
||||
/// </summary>
|
||||
private void LblClearItemFilter_Click(object sender, EventArgs e)
|
||||
{
|
||||
TxtItemFilter.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -37,9 +37,10 @@
|
||||
this.LblResourcesPath = new System.Windows.Forms.Label();
|
||||
this.BtnSearch = new System.Windows.Forms.Button();
|
||||
this.DGVTextMap = new System.Windows.Forms.DataGridView();
|
||||
this.LblClearFilter = new System.Windows.Forms.Label();
|
||||
this.ColumnHash = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.ColumnID = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.ColumnText = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
this.ColumnID = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||
((System.ComponentModel.ISupportInitialize)(this.DGVTextMap)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
@@ -47,6 +48,7 @@
|
||||
//
|
||||
resources.ApplyResources(this.TxtTextMapFilter, "TxtTextMapFilter");
|
||||
this.TxtTextMapFilter.Name = "TxtTextMapFilter";
|
||||
this.TxtTextMapFilter.TextChanged += new System.EventHandler(this.TxtTextMapFilter_TextChanged);
|
||||
this.TxtTextMapFilter.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TxtTextMapFilter_KeyDown);
|
||||
//
|
||||
// BtnSelectRecoursePath
|
||||
@@ -90,42 +92,51 @@
|
||||
//
|
||||
// DGVTextMap
|
||||
//
|
||||
resources.ApplyResources(this.DGVTextMap, "DGVTextMap");
|
||||
this.DGVTextMap.AllowUserToAddRows = false;
|
||||
this.DGVTextMap.AllowUserToDeleteRows = false;
|
||||
this.DGVTextMap.AllowUserToResizeRows = false;
|
||||
resources.ApplyResources(this.DGVTextMap, "DGVTextMap");
|
||||
this.DGVTextMap.BackgroundColor = System.Drawing.Color.White;
|
||||
this.DGVTextMap.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
this.DGVTextMap.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||
this.ColumnHash,
|
||||
this.ColumnID,
|
||||
this.ColumnText});
|
||||
this.ColumnText,
|
||||
this.ColumnID});
|
||||
this.DGVTextMap.Name = "DGVTextMap";
|
||||
this.DGVTextMap.ReadOnly = true;
|
||||
this.DGVTextMap.RowTemplate.Height = 23;
|
||||
//
|
||||
// LblClearFilter
|
||||
//
|
||||
resources.ApplyResources(this.LblClearFilter, "LblClearFilter");
|
||||
this.LblClearFilter.BackColor = System.Drawing.Color.White;
|
||||
this.LblClearFilter.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.LblClearFilter.Name = "LblClearFilter";
|
||||
this.LblClearFilter.Click += new System.EventHandler(this.LblClearFilter_Click);
|
||||
//
|
||||
// ColumnHash
|
||||
//
|
||||
resources.ApplyResources(this.ColumnHash, "ColumnHash");
|
||||
this.ColumnHash.Name = "ColumnHash";
|
||||
this.ColumnHash.ReadOnly = true;
|
||||
//
|
||||
// ColumnID
|
||||
//
|
||||
resources.ApplyResources(this.ColumnID, "ColumnID");
|
||||
this.ColumnID.Name = "ColumnID";
|
||||
this.ColumnID.ReadOnly = true;
|
||||
//
|
||||
// ColumnText
|
||||
//
|
||||
resources.ApplyResources(this.ColumnText, "ColumnText");
|
||||
this.ColumnText.Name = "ColumnText";
|
||||
this.ColumnText.ReadOnly = true;
|
||||
//
|
||||
// ColumnID
|
||||
//
|
||||
resources.ApplyResources(this.ColumnID, "ColumnID");
|
||||
this.ColumnID.Name = "ColumnID";
|
||||
this.ColumnID.ReadOnly = true;
|
||||
//
|
||||
// FormTextMapBrowser
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.LblClearFilter);
|
||||
this.Controls.Add(this.DGVTextMap);
|
||||
this.Controls.Add(this.BtnSearch);
|
||||
this.Controls.Add(this.ChkTopMost);
|
||||
@@ -151,8 +162,9 @@
|
||||
private System.Windows.Forms.Label LblResourcesPath;
|
||||
private System.Windows.Forms.Button BtnSearch;
|
||||
private System.Windows.Forms.DataGridView DGVTextMap;
|
||||
private System.Windows.Forms.Label LblClearFilter;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn ColumnHash;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn ColumnID;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn ColumnText;
|
||||
private System.Windows.Forms.DataGridViewTextBoxColumn ColumnID;
|
||||
}
|
||||
}
|
@@ -119,13 +119,12 @@ namespace GrasscutterTools.Forms
|
||||
|
||||
private void GenLines()
|
||||
{
|
||||
List<ListViewItem> items = new List<ListViewItem>(data.TextMap.Count);
|
||||
var items = new List<ListViewItem>(data.TextMap.Count);
|
||||
foreach (var kv in data.TextMap)
|
||||
{
|
||||
if (data.ManualTextMap.TryGetValue(kv.Key, out string id))
|
||||
items.Add(new ListViewItem(new string[] { kv.Key, id, kv.Value }));
|
||||
else
|
||||
items.Add(new ListViewItem(new string[] { kv.Key, "", kv.Value }));
|
||||
items.Add(data.ManualTextMap?.TryGetValue(kv.Key, out var id) == true
|
||||
? new ListViewItem(new[] { kv.Key, id, kv.Value })
|
||||
: new ListViewItem(new[] { kv.Key, "", kv.Value }));
|
||||
}
|
||||
Items = items;
|
||||
}
|
||||
@@ -161,26 +160,25 @@ namespace GrasscutterTools.Forms
|
||||
Cursor = Cursors.WaitCursor;
|
||||
Application.DoEvents();
|
||||
|
||||
var result = data.ManualTextMap.Where(kv => r.Match(kv.Value).Success)
|
||||
.Select(kv => new { Hash = kv.Key, Id = kv.Value, Text = data.TextMap[kv.Key] })
|
||||
.Concat(
|
||||
data.TextMap.Where(kv => r.Match(kv.Key).Success || r.Match(kv.Value).Success)
|
||||
.Select(kv => new
|
||||
{
|
||||
Hash = kv.Key,
|
||||
Id = data.ManualTextMap.TryGetValue(kv.Key, out string id) ? id : "",
|
||||
Text = kv.Value
|
||||
})
|
||||
).ToList();
|
||||
var manualResult = data.ManualTextMap?.Where(kv => r.Match(kv.Value).Success)
|
||||
.Select(kv => new { Hash = kv.Key, Text = data.TextMap[kv.Key], Id = kv.Value, });
|
||||
var textMapResult = data.TextMap.Where(kv => r.Match(kv.Key).Success || r.Match(kv.Value).Success)
|
||||
.Select(kv => new
|
||||
{
|
||||
Hash = kv.Key,
|
||||
Text = kv.Value,
|
||||
Id = data.ManualTextMap?.TryGetValue(kv.Key, out var id) == true ? id : "",
|
||||
});
|
||||
var result = manualResult == null ? textMapResult.ToList() : textMapResult.Concat(manualResult).ToList();
|
||||
|
||||
DGVTextMap.SuspendLayout();
|
||||
DGVTextMap.Rows.Clear();
|
||||
for (int i = 0; i < result.Count; i++)
|
||||
for (var i = 0; i < result.Count; i++)
|
||||
{
|
||||
DGVTextMap.Rows.Add();
|
||||
DGVTextMap.Rows[i].Cells[0].Value = result[i].Hash;
|
||||
DGVTextMap.Rows[i].Cells[1].Value = result[i].Id;
|
||||
DGVTextMap.Rows[i].Cells[2].Value = result[i].Text;
|
||||
DGVTextMap.Rows[i].Cells[1].Value = result[i].Text;
|
||||
DGVTextMap.Rows[i].Cells[2].Value = result[i].Id;
|
||||
}
|
||||
DGVTextMap.ResumeLayout();
|
||||
}
|
||||
@@ -195,5 +193,15 @@ namespace GrasscutterTools.Forms
|
||||
if (e.KeyCode == Keys.Enter)
|
||||
BtnSearch_Click(sender, e);
|
||||
}
|
||||
|
||||
private void TxtTextMapFilter_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
LblClearFilter.Visible = TxtTextMapFilter.Text.Length > 0;
|
||||
}
|
||||
|
||||
private void LblClearFilter_Click(object sender, EventArgs e)
|
||||
{
|
||||
TxtTextMapFilter.Clear();
|
||||
}
|
||||
}
|
||||
}
|
@@ -117,289 +117,325 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name=">>BtnSelectRecoursePath.Name" xml:space="preserve">
|
||||
<value>BtnSelectRecoursePath</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="LblLanguage.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="LblResourcesPath.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
<data name="TxtTextMapFilter.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Left, Right</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="LblResourcesPath.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>177, 15</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>BtnSearch.Name" xml:space="preserve">
|
||||
<value>BtnSearch</value>
|
||||
</data>
|
||||
<data name=">>LblLanguage.Name" xml:space="preserve">
|
||||
<value>LblLanguage</value>
|
||||
</data>
|
||||
<data name="ColumnText.HeaderText" xml:space="preserve">
|
||||
<value>Text</value>
|
||||
</data>
|
||||
<data name="BtnSearch.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>8</value>
|
||||
</data>
|
||||
<data name="LblLanguage.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="TxtTextMapFilter.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>12, 41</value>
|
||||
</data>
|
||||
<data name=">>DGVTextMap.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DataGridView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>LblLanguage.ZOrder" xml:space="preserve">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="BtnSelectRecoursePath.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>96, 12</value>
|
||||
</data>
|
||||
<data name="ColumnHash.Width" type="System.Int32, mscorlib">
|
||||
<value>80</value>
|
||||
</data>
|
||||
<data name="DGVTextMap.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
|
||||
<value>CenterScreen</value>
|
||||
</data>
|
||||
<data name="ColumnID.Width" type="System.Int32, mscorlib">
|
||||
<value>240</value>
|
||||
</data>
|
||||
<data name="LblResourcesPath.Text" xml:space="preserve">
|
||||
<value>请选择Resources路径</value>
|
||||
</data>
|
||||
<data name=">>LblResourcesPath.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name="LblLanguage.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>32, 17</value>
|
||||
</data>
|
||||
<data name=">>LblLanguage.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="LblResourcesPath.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>327, 17</value>
|
||||
</data>
|
||||
<data name="TxtTextMapFilter.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>555, 23</value>
|
||||
</data>
|
||||
<data name="$this.Text" xml:space="preserve">
|
||||
<value>文本映射表浏览器</value>
|
||||
</data>
|
||||
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="DGVTextMap.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>636, 379</value>
|
||||
</data>
|
||||
<data name=">>BtnSearch.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>LblResourcesPath.ZOrder" xml:space="preserve">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="CmbLanguage.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name="ChkTopMost.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name=">>LblResourcesPath.Name" xml:space="preserve">
|
||||
<value>LblResourcesPath</value>
|
||||
</data>
|
||||
<data name="ChkTopMost.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>7</value>
|
||||
</data>
|
||||
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="TxtTextMapFilter.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name=">>ColumnText.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DataGridViewTextBoxColumn, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>TxtTextMapFilter.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="ColumnHash.HeaderText" xml:space="preserve">
|
||||
<value>Hash</value>
|
||||
</data>
|
||||
<data name="ColumnText.Width" type="System.Int32, mscorlib">
|
||||
<value>250</value>
|
||||
</data>
|
||||
<data name="CmbLanguage.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>548, 12</value>
|
||||
</data>
|
||||
<data name=">>TxtTextMapFilter.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>DGVTextMap.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name=">>BtnSelectRecoursePath.ZOrder" xml:space="preserve">
|
||||
<value>6</value>
|
||||
</data>
|
||||
<data name="CmbLanguage.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>100, 25</value>
|
||||
</data>
|
||||
<data name="BtnSearch.Text" xml:space="preserve">
|
||||
<value>搜索</value>
|
||||
</data>
|
||||
<data name="CmbLanguage.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name=">>DGVTextMap.Name" xml:space="preserve">
|
||||
<value>DGVTextMap</value>
|
||||
</data>
|
||||
<data name="LblResourcesPath.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Left, Right</value>
|
||||
</data>
|
||||
<data name=">>ColumnHash.Name" xml:space="preserve">
|
||||
<value>ColumnHash</value>
|
||||
</data>
|
||||
<data name=">>BtnSearch.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="DGVTextMap.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>9</value>
|
||||
</data>
|
||||
<data name=">>BtnSelectRecoursePath.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="BtnSelectRecoursePath.Text" xml:space="preserve">
|
||||
<value>浏览</value>
|
||||
</data>
|
||||
<data name="LblLanguage.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>510, 15</value>
|
||||
</data>
|
||||
<data name=">>LblResourcesPath.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>CmbLanguage.ZOrder" xml:space="preserve">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name=">>ChkTopMost.Name" xml:space="preserve">
|
||||
<value>ChkTopMost</value>
|
||||
</data>
|
||||
<data name="$this.Font" type="System.Drawing.Font, System.Drawing">
|
||||
<value>微软雅黑, 9pt</value>
|
||||
</data>
|
||||
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>660, 461</value>
|
||||
</data>
|
||||
<data name=">>CmbLanguage.Name" xml:space="preserve">
|
||||
<value>CmbLanguage</value>
|
||||
</data>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>7, 17</value>
|
||||
</data>
|
||||
<data name=">>BtnSearch.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name=">>ColumnID.Name" xml:space="preserve">
|
||||
<value>ColumnID</value>
|
||||
</data>
|
||||
<data name="TxtTextMapFilter.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Left, Right</value>
|
||||
</data>
|
||||
<data name=">>ChkTopMost.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="LblLanguage.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="ColumnID.HeaderText" xml:space="preserve">
|
||||
<value>ID</value>
|
||||
</data>
|
||||
<data name="BtnSearch.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name=">>ChkTopMost.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>ColumnText.Name" xml:space="preserve">
|
||||
<value>ColumnText</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>FormTextMapBrowser</value>
|
||||
</data>
|
||||
<data name=">>CmbLanguage.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>DGVTextMap.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name="BtnSearch.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>573, 41</value>
|
||||
</data>
|
||||
<data name=">>BtnSelectRecoursePath.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>ChkTopMost.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>ColumnHash.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DataGridViewTextBoxColumn, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>TxtTextMapFilter.ZOrder" xml:space="preserve">
|
||||
<value>7</value>
|
||||
</data>
|
||||
<data name=">>TxtTextMapFilter.Name" xml:space="preserve">
|
||||
<value>TxtTextMapFilter</value>
|
||||
</data>
|
||||
<data name="DGVTextMap.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>12, 70</value>
|
||||
<data name=">>TxtTextMapFilter.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>LblLanguage.Parent" xml:space="preserve">
|
||||
<data name=">>TxtTextMapFilter.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name="LblLanguage.Text" xml:space="preserve">
|
||||
<value>语言</value>
|
||||
<data name=">>TxtTextMapFilter.ZOrder" xml:space="preserve">
|
||||
<value>8</value>
|
||||
</data>
|
||||
<data name="ChkTopMost.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>51, 21</value>
|
||||
</data>
|
||||
<data name="BtnSelectRecoursePath.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name=">>CmbLanguage.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name="ChkTopMost.Text" xml:space="preserve">
|
||||
<value>置顶</value>
|
||||
</data>
|
||||
<data name="BtnSearch.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>75, 23</value>
|
||||
</data>
|
||||
<data name=">>ColumnID.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DataGridViewTextBoxColumn, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<data name="BtnSelectRecoursePath.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>96, 12</value>
|
||||
</data>
|
||||
<data name="BtnSelectRecoursePath.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>75, 23</value>
|
||||
</data>
|
||||
<data name="$this.MinimumSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>600, 400</value>
|
||||
<data name="BtnSelectRecoursePath.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="BtnSelectRecoursePath.Text" xml:space="preserve">
|
||||
<value>浏览</value>
|
||||
</data>
|
||||
<data name=">>BtnSelectRecoursePath.Name" xml:space="preserve">
|
||||
<value>BtnSelectRecoursePath</value>
|
||||
</data>
|
||||
<data name=">>BtnSelectRecoursePath.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>BtnSelectRecoursePath.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>BtnSelectRecoursePath.ZOrder" xml:space="preserve">
|
||||
<value>7</value>
|
||||
</data>
|
||||
<data name="CmbLanguage.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name="CmbLanguage.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>548, 12</value>
|
||||
</data>
|
||||
<data name="CmbLanguage.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>100, 25</value>
|
||||
</data>
|
||||
<data name="CmbLanguage.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name=">>CmbLanguage.Name" xml:space="preserve">
|
||||
<value>CmbLanguage</value>
|
||||
</data>
|
||||
<data name=">>CmbLanguage.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>CmbLanguage.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>CmbLanguage.ZOrder" xml:space="preserve">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="LblLanguage.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name="LblLanguage.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="LblLanguage.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>510, 15</value>
|
||||
</data>
|
||||
<data name="LblLanguage.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>32, 17</value>
|
||||
</data>
|
||||
<data name="LblLanguage.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="LblLanguage.Text" xml:space="preserve">
|
||||
<value>语言</value>
|
||||
</data>
|
||||
<data name=">>LblLanguage.Name" xml:space="preserve">
|
||||
<value>LblLanguage</value>
|
||||
</data>
|
||||
<data name=">>LblLanguage.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>LblLanguage.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>LblLanguage.ZOrder" xml:space="preserve">
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name="ChkTopMost.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="ChkTopMost.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>12, 14</value>
|
||||
</data>
|
||||
<metadata name="ColumnText.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="ColumnID.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="ChkTopMost.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>51, 21</value>
|
||||
</data>
|
||||
<data name="ChkTopMost.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>7</value>
|
||||
</data>
|
||||
<data name="ChkTopMost.Text" xml:space="preserve">
|
||||
<value>置顶</value>
|
||||
</data>
|
||||
<data name=">>ChkTopMost.Name" xml:space="preserve">
|
||||
<value>ChkTopMost</value>
|
||||
</data>
|
||||
<data name=">>ChkTopMost.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>ChkTopMost.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>ChkTopMost.ZOrder" xml:space="preserve">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="LblResourcesPath.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Left, Right</value>
|
||||
</data>
|
||||
<data name="LblResourcesPath.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>177, 15</value>
|
||||
</data>
|
||||
<data name="LblResourcesPath.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>327, 17</value>
|
||||
</data>
|
||||
<data name="LblResourcesPath.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="LblResourcesPath.Text" xml:space="preserve">
|
||||
<value>请选择Resources路径</value>
|
||||
</data>
|
||||
<data name=">>LblResourcesPath.Name" xml:space="preserve">
|
||||
<value>LblResourcesPath</value>
|
||||
</data>
|
||||
<data name=">>LblResourcesPath.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>LblResourcesPath.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>LblResourcesPath.ZOrder" xml:space="preserve">
|
||||
<value>6</value>
|
||||
</data>
|
||||
<data name="BtnSearch.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name="BtnSearch.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>573, 41</value>
|
||||
</data>
|
||||
<data name="BtnSearch.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>75, 23</value>
|
||||
</data>
|
||||
<data name="BtnSearch.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>8</value>
|
||||
</data>
|
||||
<data name="BtnSearch.Text" xml:space="preserve">
|
||||
<value>搜索</value>
|
||||
</data>
|
||||
<data name=">>BtnSearch.Name" xml:space="preserve">
|
||||
<value>BtnSearch</value>
|
||||
</data>
|
||||
<data name=">>BtnSearch.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>BtnSearch.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>BtnSearch.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="DGVTextMap.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<metadata name="ColumnHash.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="ColumnHash.HeaderText" xml:space="preserve">
|
||||
<value>Hash</value>
|
||||
</data>
|
||||
<data name="ColumnHash.Width" type="System.Int32, mscorlib">
|
||||
<value>80</value>
|
||||
</data>
|
||||
<metadata name="ColumnText.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="ColumnText.HeaderText" xml:space="preserve">
|
||||
<value>Text</value>
|
||||
</data>
|
||||
<data name="ColumnText.Width" type="System.Int32, mscorlib">
|
||||
<value>250</value>
|
||||
</data>
|
||||
<metadata name="ColumnID.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="ColumnID.HeaderText" xml:space="preserve">
|
||||
<value>ID</value>
|
||||
</data>
|
||||
<data name="ColumnID.Width" type="System.Int32, mscorlib">
|
||||
<value>240</value>
|
||||
</data>
|
||||
<data name="DGVTextMap.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>12, 70</value>
|
||||
</data>
|
||||
<data name="DGVTextMap.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>636, 379</value>
|
||||
</data>
|
||||
<data name="DGVTextMap.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>9</value>
|
||||
</data>
|
||||
<data name=">>DGVTextMap.Name" xml:space="preserve">
|
||||
<value>DGVTextMap</value>
|
||||
</data>
|
||||
<data name=">>DGVTextMap.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DataGridView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>DGVTextMap.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>DGVTextMap.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>545, 44</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>16, 17</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>18</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Text" xml:space="preserve">
|
||||
<value>X</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Visible" type="System.Boolean, mscorlib">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.Name" xml:space="preserve">
|
||||
<value>LblClearFilter</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>7, 17</value>
|
||||
</data>
|
||||
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>660, 461</value>
|
||||
</data>
|
||||
<data name="$this.Font" type="System.Drawing.Font, System.Drawing">
|
||||
<value>微软雅黑, 9pt</value>
|
||||
</data>
|
||||
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>4, 4, 4, 4</value>
|
||||
</data>
|
||||
<data name="$this.MinimumSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>600, 400</value>
|
||||
</data>
|
||||
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
|
||||
<value>CenterScreen</value>
|
||||
</data>
|
||||
<data name="$this.Text" xml:space="preserve">
|
||||
<value>文本映射表浏览器</value>
|
||||
</data>
|
||||
<data name=">>ColumnHash.Name" xml:space="preserve">
|
||||
<value>ColumnHash</value>
|
||||
</data>
|
||||
<data name=">>ColumnHash.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DataGridViewTextBoxColumn, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>ColumnText.Name" xml:space="preserve">
|
||||
<value>ColumnText</value>
|
||||
</data>
|
||||
<data name=">>ColumnText.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DataGridViewTextBoxColumn, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>ColumnID.Name" xml:space="preserve">
|
||||
<value>ColumnID</value>
|
||||
</data>
|
||||
<data name=">>ColumnID.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.DataGridViewTextBoxColumn, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>$this.Name" xml:space="preserve">
|
||||
<value>FormTextMapBrowser</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
</root>
|
@@ -26,7 +26,7 @@ namespace GrasscutterTools.GOOD
|
||||
/// Doc: https://frzyc.github.io/genshin-optimizer/#/doc
|
||||
/// Modified from https://github.com/Andrewthe13th/Inventory_Kamera/blob/master/InventoryKamera/game/Artifact.cs
|
||||
/// </summary>
|
||||
public class Artifact
|
||||
internal class Artifact
|
||||
{
|
||||
/// <summary>
|
||||
/// e.g. "GladiatorsFinale"
|
||||
|
@@ -26,7 +26,7 @@ namespace GrasscutterTools.GOOD
|
||||
/// Doc: https://frzyc.github.io/genshin-optimizer/#/doc
|
||||
/// Modified from https://github.com/Andrewthe13th/Inventory_Kamera/blob/master/InventoryKamera/game/Character.cs
|
||||
/// </summary>
|
||||
public class Character
|
||||
internal class Character
|
||||
{
|
||||
/// <summary>
|
||||
/// e.g. "Rosaria"
|
||||
|
@@ -38,7 +38,7 @@ namespace GrasscutterTools.GOOD
|
||||
/// https://genshin.mingyulab.com/
|
||||
/// https://genshin-center.com/
|
||||
/// </summary>
|
||||
public class GOOD
|
||||
internal class GOOD
|
||||
{
|
||||
[JsonProperty("format")]
|
||||
public string Format { get; set; }
|
||||
|
@@ -26,7 +26,7 @@ using GrasscutterTools.Properties;
|
||||
|
||||
namespace GrasscutterTools.GOOD
|
||||
{
|
||||
public static class GOODData
|
||||
internal static class GOODData
|
||||
{
|
||||
static GOODData()
|
||||
{
|
||||
|
@@ -28,7 +28,7 @@ namespace GrasscutterTools.GOOD
|
||||
/// Doc: https://frzyc.github.io/genshin-optimizer/#/doc
|
||||
/// Modified from https://github.com/Andrewthe13th/Inventory_Kamera/blob/master/InventoryKamera/game/Weapon.cs
|
||||
/// </summary>
|
||||
public class Weapon
|
||||
internal class Weapon
|
||||
{
|
||||
/// <summary>
|
||||
/// e.g. "CrescentPike"
|
||||
|
@@ -24,7 +24,7 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Activity
|
||||
{
|
||||
public class ActivityConfigItem
|
||||
internal class ActivityConfigItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 活动ID
|
||||
|
@@ -162,6 +162,21 @@ namespace GrasscutterTools.Game
|
||||
/// </summary>
|
||||
public static readonly Version V1_6_3 = new Version(1, 6, 3);
|
||||
|
||||
/// <summary>
|
||||
/// 2023/9/1
|
||||
/// </summary>
|
||||
public static readonly Version V1_7_0 = new Version(1, 7, 0);
|
||||
|
||||
/// <summary>
|
||||
/// 2023/9/3
|
||||
/// </summary>
|
||||
public static readonly Version V1_7_1 = new Version(1, 7, 1);
|
||||
|
||||
/// <summary>
|
||||
/// 2023/10/1
|
||||
/// </summary>
|
||||
public static readonly Version V1_7_2 = new Version(1, 7, 2);
|
||||
|
||||
// More...
|
||||
/// <summary>
|
||||
/// Date
|
||||
@@ -184,6 +199,9 @@ namespace GrasscutterTools.Game
|
||||
V1_6_1,
|
||||
V1_6_2,
|
||||
V1_6_3,
|
||||
V1_7_0,
|
||||
V1_7_1,
|
||||
V1_7_2,
|
||||
};
|
||||
|
||||
#endregion - 版本列表 Version List -
|
||||
|
@@ -17,10 +17,12 @@
|
||||
*
|
||||
**/
|
||||
|
||||
using GrasscutterTools.Game.Data;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.CutScene
|
||||
{
|
||||
[ResourceType("CutsceneExcelConfigData.json")]
|
||||
internal class CutSceneItem
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
|
32
Source/GrasscutterTools/Game/Data/Excels/AchievementData.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("AchievementExcelConfigData.json")]
|
||||
internal class AchievementData : GameResource
|
||||
{
|
||||
[JsonProperty("isDisuse")]
|
||||
public bool IsDisuse { get; set; }
|
||||
|
||||
public bool IsUsed => !IsDisuse;
|
||||
}
|
||||
}
|
33
Source/GrasscutterTools/Game/Data/Excels/AvatarData.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using GrasscutterTools.Game.Props;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("AvatarExcelConfigData.json")]
|
||||
internal class AvatarData : GameResource
|
||||
{
|
||||
[JsonProperty("qualityType"), JsonConverter(typeof(StringEnumConverter))]
|
||||
public QualityType QualityType { get; set; }
|
||||
}
|
||||
}
|
30
Source/GrasscutterTools/Game/Data/Excels/DungeonData.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("DungeonExcelConfigData.json")]
|
||||
internal class DungeonData : GameResource
|
||||
{
|
||||
[JsonProperty("sceneId")]
|
||||
public int SceneId { get; set; }
|
||||
}
|
||||
}
|
36
Source/GrasscutterTools/Game/Data/Excels/GadgetData.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("GadgetExcelConfigData.json")]
|
||||
internal class GadgetData : GameResource
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("jsonName")]
|
||||
public string JsonName { get; set; }
|
||||
|
||||
[JsonProperty("interactNameTextMapHash")]
|
||||
public long InteractNameTextMapHash { get; set; }
|
||||
}
|
||||
}
|
33
Source/GrasscutterTools/Game/Data/Excels/GatherData.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("GatherExcelConfigData.json")]
|
||||
internal class GatherData
|
||||
{
|
||||
[JsonProperty("gadgetId")]
|
||||
public int GadgetId { get; set; }
|
||||
|
||||
[JsonProperty("itemId")]
|
||||
public int ItemId { get; set; }
|
||||
}
|
||||
}
|
33
Source/GrasscutterTools/Game/Data/Excels/HomeWorldBgmData.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("HomeWorldBgmExcelConfigData.json")]
|
||||
internal class HomeWorldBgmData : GameResource
|
||||
{
|
||||
[JsonProperty("homeBgmId")]
|
||||
public override int Id { get; set; }
|
||||
|
||||
[JsonProperty("bgmNameTextMapHash")]
|
||||
public long BgmNameTextMapHash { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("HomeWorldFurnitureExcelConfigData.json")]
|
||||
internal class HomeWorldFurnitureData : GameResource
|
||||
{
|
||||
[JsonProperty("furnitureGadgetID")]
|
||||
public int[] FurnitureGadgetId { get; set; }
|
||||
}
|
||||
}
|
26
Source/GrasscutterTools/Game/Data/Excels/MainQuestData.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("MainQuestExcelConfigData.json")]
|
||||
internal class MainQuestData : GameResource
|
||||
{
|
||||
}
|
||||
}
|
42
Source/GrasscutterTools/Game/Data/Excels/MaterialData.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using GrasscutterTools.Game.Inventory;
|
||||
using GrasscutterTools.Game.Props;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("MaterialExcelConfigData.json")]
|
||||
internal class MaterialData : GameResource
|
||||
{
|
||||
[JsonProperty("itemType"), JsonConverter(typeof(StringEnumConverter))]
|
||||
public ItemType ItemType { get; set; }
|
||||
|
||||
[JsonProperty("materialType"), JsonConverter(typeof(StringEnumConverter))]
|
||||
public MaterialType MaterialType { get; set; }
|
||||
|
||||
[JsonProperty("itemUse")]
|
||||
public List<ItemUseData> ItemUse { get; set; }
|
||||
}
|
||||
}
|
35
Source/GrasscutterTools/Game/Data/Excels/MonsterData.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using GrasscutterTools.Game.Props;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("MonsterExcelConfigData.json")]
|
||||
internal class MonsterData : GameResource
|
||||
{
|
||||
[JsonProperty("monsterName")]
|
||||
public string MonsterName { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public MonsterType Type { get; set; }
|
||||
}
|
||||
}
|
36
Source/GrasscutterTools/Game/Data/Excels/QuestData.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("QuestExcelConfigData.json")]
|
||||
internal class QuestData : GameResource
|
||||
{
|
||||
[JsonProperty("subId")]
|
||||
public override int Id { get; set; }
|
||||
|
||||
[JsonProperty("mainId")]
|
||||
public int MainId { get; set; }
|
||||
|
||||
[JsonProperty("order")]
|
||||
public int Order { get; set; }
|
||||
}
|
||||
}
|
26
Source/GrasscutterTools/Game/Data/Excels/ReliquaryData.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("ReliquaryExcelConfigData.json")]
|
||||
internal class ReliquaryData : GameResource
|
||||
{
|
||||
}
|
||||
}
|
35
Source/GrasscutterTools/Game/Data/Excels/SceneData.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using GrasscutterTools.Game.Props;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("SceneExcelConfigData.json")]
|
||||
internal class SceneData : GameResource
|
||||
{
|
||||
[JsonProperty("type")]
|
||||
public SceneType SceneType { get; set; }
|
||||
|
||||
[JsonProperty("scriptData")]
|
||||
public string ScriptData { get; set; }
|
||||
}
|
||||
}
|
39
Source/GrasscutterTools/Game/Data/Excels/SceneTagData.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("SceneTagConfigData.json")]
|
||||
internal class SceneTagData
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[JsonProperty("sceneTagName")]
|
||||
public string SceneTagName { get; set; }
|
||||
|
||||
[JsonProperty("sceneId")]
|
||||
public int SceneId { get; set; }
|
||||
|
||||
[JsonProperty("isDefaultValid")]
|
||||
public bool IsDefaultValid { get; set; }
|
||||
}
|
||||
}
|
30
Source/GrasscutterTools/Game/Data/Excels/WeaponData.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("WeaponExcelConfigData.json")]
|
||||
internal class WeaponData : GameResource
|
||||
{
|
||||
[JsonProperty("rankLevel")]
|
||||
public int RankLevel { get; set; }
|
||||
}
|
||||
}
|
42
Source/GrasscutterTools/Game/Data/Excels/WeatherData.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data.Excels
|
||||
{
|
||||
[ResourceType("WeatherExcelConfigData.json")]
|
||||
internal class WeatherData
|
||||
{
|
||||
[JsonProperty("areaID")]
|
||||
public int AreaId { get; set; }
|
||||
|
||||
[JsonProperty("weatherAreaId")]
|
||||
public int WeatherAreaId { get; set; }
|
||||
|
||||
[JsonProperty("profileName")]
|
||||
public string ProfileName { get; set; }
|
||||
|
||||
[JsonProperty("defaultClimate")]
|
||||
public string DefaultClimate { get; set; }
|
||||
|
||||
[JsonProperty("sceneID")]
|
||||
public int SceneId { get; set; }
|
||||
}
|
||||
}
|
38
Source/GrasscutterTools/Game/Data/GameResource.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data
|
||||
{
|
||||
internal abstract class GameResource
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public virtual int Id { get; set; }
|
||||
|
||||
[JsonProperty("nameTextMapHash")]
|
||||
public long NameTextMapHash { get; set; }
|
||||
|
||||
[JsonProperty("titleTextMapHash")]
|
||||
public long TitleTextMapHash { get; set; }
|
||||
|
||||
[JsonProperty("descTextMapHash")]
|
||||
public long DescTextMapHash { get; set; }
|
||||
}
|
||||
}
|
543
Source/GrasscutterTools/Game/Data/GameResources.cs
Normal file
@@ -0,0 +1,543 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using GrasscutterTools.Game.CutScene;
|
||||
using GrasscutterTools.Game.Data.Excels;
|
||||
using GrasscutterTools.Game.Inventory;
|
||||
using GrasscutterTools.Game.Props;
|
||||
using GrasscutterTools.Utils;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Data
|
||||
{
|
||||
internal class GameResources
|
||||
{
|
||||
public Dictionary<int, AchievementData> AchievementData { get; set; }
|
||||
|
||||
public Dictionary<int, AvatarData> AvatarData { get; set; }
|
||||
|
||||
public Dictionary<int, HomeWorldBgmData> HomeWorldBgmData { get; set; }
|
||||
|
||||
public Dictionary<int, DungeonData> DungeonData { get; set; }
|
||||
|
||||
public Dictionary<int, GadgetData> GadgetData { get; set; }
|
||||
|
||||
public List<GatherData> GatherData { get; set; }
|
||||
|
||||
public Dictionary<int, HomeWorldFurnitureData> HomeWorldFurnitureData { get; set; }
|
||||
|
||||
public Dictionary<int, MainQuestData> MainQuestData { get; set; }
|
||||
|
||||
public Dictionary<int, QuestData> QuestData { get; set; }
|
||||
|
||||
public Dictionary<int, MaterialData> MaterialData { get; set; }
|
||||
|
||||
public Dictionary<int, MonsterData> MonsterData { get; set; }
|
||||
|
||||
public Dictionary<int, ReliquaryData> ReliquaryData { get; set; }
|
||||
|
||||
public Dictionary<int, SceneData> SceneData { get; set; }
|
||||
|
||||
public List<SceneTagData> SceneTagData { get; set; }
|
||||
|
||||
public Dictionary<int, WeaponData> WeaponData { get; set; }
|
||||
|
||||
public TextMapData TextMapData { get; set; }
|
||||
|
||||
public List<WeatherData> WeatherData { get; set; }
|
||||
public List<CutSceneItem> CutSceneData { get; set; }
|
||||
|
||||
public GameResources(string resourcesDirPath, TextMapData textMapData)
|
||||
{
|
||||
TextMapData = textMapData;
|
||||
|
||||
var properties = typeof(GameResources).GetProperties();
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var type = property.PropertyType;
|
||||
if (!type.IsGenericType) continue;
|
||||
var genericArguments = type.GetGenericArguments();
|
||||
ResourceTypeAttribute attribute = null;
|
||||
foreach (var it in genericArguments)
|
||||
{
|
||||
var attributes = it.GetCustomAttributes(typeof(ResourceTypeAttribute), true);
|
||||
if (attributes.Length == 0) continue;
|
||||
attribute = (ResourceTypeAttribute)attributes[0];
|
||||
type = it;
|
||||
}
|
||||
if (attribute == null) continue;
|
||||
var dataFile = Path.Combine(resourcesDirPath, "ExcelBinOutput", attribute.Name);
|
||||
var data = LoadDataFile(type, dataFile);
|
||||
property.SetValue(this, data, null);
|
||||
}
|
||||
|
||||
var illegalWeaponIds = new SparseSet(
|
||||
"10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509," +
|
||||
"13503, 13506, 14411, 14503, 14508, 15504-15506, 20001");
|
||||
foreach (var id in WeaponData.Keys.Where(id => illegalWeaponIds.Contains(id)).ToList())
|
||||
WeaponData.Remove(id);
|
||||
|
||||
var illegalRelicIds = new SparseSet(
|
||||
"20002, 20004, 23300-24825"
|
||||
);
|
||||
//var illegalRelicIds = new SparseSet(
|
||||
// "20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554"
|
||||
//);
|
||||
foreach (var id in ReliquaryData.Keys.Where(id => illegalRelicIds.Contains(id)).ToList())
|
||||
ReliquaryData.Remove(id);
|
||||
|
||||
var illegalItemIds = new SparseSet(
|
||||
"3004-3008, 3018-3022"
|
||||
);
|
||||
//var illegalItemIds = new SparseSet(
|
||||
// "3004-3008, 3018-3022, 100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000," +
|
||||
// "105001, 105004, 106000-107000, 107011, 108000, 109000-110000," +
|
||||
// "115000-130000, 200200-200899, 220050, 220054"
|
||||
//);
|
||||
foreach (var id in MaterialData.Keys.Where(id => illegalItemIds.Contains(id)).ToList())
|
||||
MaterialData.Remove(id);
|
||||
|
||||
foreach (var id in AvatarData.Keys.Where(id => id < 10000002 || id >= 11000000).ToList())
|
||||
AvatarData.Remove(id);
|
||||
}
|
||||
|
||||
private static object LoadDataFile(Type type, string path)
|
||||
{
|
||||
IList list = null;
|
||||
try
|
||||
{
|
||||
list = (IList)JsonConvert.DeserializeObject(File.ReadAllText(path), typeof(List<>).MakeGenericType(type));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to load \"{path}\", Exception={ex}");
|
||||
}
|
||||
if (type.IsSubclassOf(typeof(GameResource)))
|
||||
{
|
||||
var dicType = typeof(Dictionary<,>).MakeGenericType(typeof(int), type);
|
||||
var dic = (IDictionary)Activator.CreateInstance(dicType);
|
||||
if (list != null)
|
||||
{
|
||||
foreach (GameResource gameResource in list)
|
||||
{
|
||||
if (gameResource.Id == 0) continue;
|
||||
dic.Add(gameResource.Id, gameResource);
|
||||
}
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (list == null)
|
||||
list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(type));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, string> Languages = new Dictionary<string, string>
|
||||
{
|
||||
["zh-cn"] = "TextMapCHS",
|
||||
["zh-tw"] = "TextMapCHT",
|
||||
["en-us"] = "TextMapEN",
|
||||
["ru-ru"] = "TextMapRU",
|
||||
};
|
||||
|
||||
public void ConvertResources(string projectResourcesDir)
|
||||
{
|
||||
var currentCultureInfo = Thread.CurrentThread.CurrentUICulture;
|
||||
try
|
||||
{
|
||||
var sb = new StringBuilder(MaterialData.Count * 24);
|
||||
foreach (var language in Languages)
|
||||
{
|
||||
var dir = Path.Combine(projectResourcesDir, language.Key);
|
||||
TextMapData.LoadTextMap(TextMapData.TextMapFilePaths[Array.IndexOf(TextMapData.TextMapFiles, language.Value)]);
|
||||
|
||||
Thread.CurrentThread.CurrentUICulture = new CultureInfo(language.Key);
|
||||
GameData.LoadResources();
|
||||
|
||||
#region Achievement
|
||||
|
||||
// Achievement
|
||||
File.WriteAllLines(
|
||||
Path.Combine(dir, "Achievement.txt"),
|
||||
AchievementData.Values.Where(it => it.IsUsed)
|
||||
.Select(it => $"{it.Id}:{TextMapData.GetText(it.TitleTextMapHash.ToString())} - {TextMapData.GetText(it.DescTextMapHash.ToString())}"),
|
||||
Encoding.UTF8);
|
||||
|
||||
#endregion Achievement
|
||||
|
||||
#region Artifact
|
||||
|
||||
// Artifact
|
||||
File.WriteAllLines(
|
||||
Path.Combine(dir, "Artifact.txt"),
|
||||
ReliquaryData.Values.OrderBy(it => it.Id).Select(it => $"{it.Id}:{TextMapData.GetText(it.NameTextMapHash.ToString())}"),
|
||||
Encoding.UTF8);
|
||||
|
||||
#endregion Artifact
|
||||
|
||||
#region Avatar
|
||||
|
||||
// Avatar
|
||||
File.WriteAllLines(
|
||||
Path.Combine(dir, "Avatar.txt"),
|
||||
MaterialData.Values
|
||||
.Where(it => it.MaterialType == MaterialType.MATERIAL_AVATAR)
|
||||
.Select(it => $"{it.Id}:{TextMapData.GetText(it.NameTextMapHash.ToString())}"),
|
||||
Encoding.UTF8);
|
||||
|
||||
#endregion Avatar
|
||||
|
||||
#region Dungeon
|
||||
|
||||
// Dungeon
|
||||
sb.Clear();
|
||||
foreach (var it in DungeonData.Values)
|
||||
{
|
||||
if (!TextMapData.TryGetText(it.NameTextMapHash.ToString(), out var name))
|
||||
{
|
||||
var temp = GameData.Dungeons[it.Id];
|
||||
if (temp != ItemMap.EmptyName)
|
||||
name = temp;
|
||||
}
|
||||
|
||||
sb.AppendFormat("{0}:{1}", it.Id, name).AppendLine();
|
||||
}
|
||||
File.WriteAllText(
|
||||
Path.Combine(dir, "Dungeon.txt"),
|
||||
sb.ToString(),
|
||||
Encoding.UTF8);
|
||||
//File.WriteAllLines(
|
||||
// Path.Combine(dir, "Dungeon.txt"),
|
||||
// DungeonData.Values.Select(it => $"{it.Id}:{TextMapData.GetText(it.NameTextMapHash.ToString())}"),
|
||||
// Encoding.UTF8);
|
||||
|
||||
#endregion Dungeon
|
||||
|
||||
#region Gadget
|
||||
|
||||
// Gadget
|
||||
sb.Clear();
|
||||
var gatherMap = new Dictionary<int, int>(GatherData.Count);
|
||||
foreach (var it in GatherData.Where(it => !gatherMap.ContainsKey(it.GadgetId)))
|
||||
gatherMap.Add(it.GadgetId, it.ItemId);
|
||||
var furnitureMap = new Dictionary<int, long>(HomeWorldFurnitureData.Count);
|
||||
foreach (var it in HomeWorldFurnitureData.Values.Where(it => it.FurnitureGadgetId != null))
|
||||
foreach (var gadgetId in it.FurnitureGadgetId.Where(id => id > 0 && !furnitureMap.ContainsKey(id)))
|
||||
furnitureMap.Add(gadgetId, it.NameTextMapHash);
|
||||
var oldFirst = language.Key.StartsWith("zh");
|
||||
foreach (var gadgetTypes in GadgetData.Values.OrderBy(it => it.Id).GroupBy(it => it.Type))
|
||||
{
|
||||
sb.Append("// ").AppendLine(GadgetType.ToTranslatedString(gadgetTypes.Key, language.Key));
|
||||
foreach (var it in gadgetTypes)
|
||||
{
|
||||
var name = oldFirst ? GameData.Gadgets[it.Id] : ItemMap.EmptyName;
|
||||
|
||||
if (name == ItemMap.EmptyName)
|
||||
{
|
||||
if (!TextMapData.TryGetText(it.NameTextMapHash.ToString(), out name)
|
||||
&& !TextMapData.TryGetText(it.InteractNameTextMapHash.ToString(), out name))
|
||||
{
|
||||
if (gatherMap.TryGetValue(it.Id, out var itemId)
|
||||
&& MaterialData.TryGetValue(itemId, out var item))
|
||||
{
|
||||
name = TextMapData.GetText(item.NameTextMapHash.ToString());
|
||||
}
|
||||
else if (furnitureMap.TryGetValue(it.Id, out var hash))
|
||||
{
|
||||
name = TextMapData.GetText(hash.ToString());
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(it.JsonName))
|
||||
{
|
||||
name = it.JsonName;
|
||||
}
|
||||
else if (!oldFirst)
|
||||
{
|
||||
var temp = GameData.Gadgets[it.Id];
|
||||
if (temp != ItemMap.EmptyName)
|
||||
name = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendFormat("{0}:{1}", it.Id, name).AppendLine();
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
// 旧的数据
|
||||
//var old = GameData.Gadgets.AllIds.Where(it => !GadgetData.ContainsKey(it));
|
||||
//if (old.Any())
|
||||
//{
|
||||
// sb.AppendLine("// Old lines");
|
||||
// foreach (var it in old)
|
||||
// sb.AppendFormat("{0}:{1}", it, GameData.Gadgets[it]).AppendLine();
|
||||
//}
|
||||
|
||||
File.WriteAllText(
|
||||
Path.Combine(dir, "Gadget.txt"),
|
||||
sb.ToString(),
|
||||
Encoding.UTF8);
|
||||
|
||||
#endregion Gadget
|
||||
|
||||
#region Item
|
||||
|
||||
// Item
|
||||
sb.Clear();
|
||||
foreach (var itemTypes in MaterialData.Values.GroupBy(it => it.ItemType))
|
||||
{
|
||||
sb.Append("// ").AppendLine(itemTypes.Key.ToTranslatedString(language.Key));
|
||||
if (itemTypes.Key == ItemType.ITEM_MATERIAL)
|
||||
{
|
||||
foreach (var m in itemTypes
|
||||
.GroupBy(it => it.MaterialType)
|
||||
.Where(it => it.Key != MaterialType.MATERIAL_NONE)
|
||||
.OrderBy(it => it.Average(m => m.Id)))
|
||||
{
|
||||
sb.Append("// ").AppendLine(m.Key.ToTranslatedString(language.Key));
|
||||
|
||||
if (m.Key == MaterialType.MATERIAL_BGM)
|
||||
{
|
||||
foreach (var materialData in m)
|
||||
{
|
||||
var param = int.Parse(materialData.ItemUse[0].UseParam[0]);
|
||||
var name = HomeWorldBgmData.ContainsKey(param) ? TextMapData.GetText(
|
||||
HomeWorldBgmData[param].BgmNameTextMapHash.ToString()) : string.Empty;
|
||||
sb.AppendFormat("{0}:{1} - {2}",
|
||||
materialData.Id,
|
||||
TextMapData.GetText(materialData.NameTextMapHash.ToString()),
|
||||
name);
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var materialData in m)
|
||||
sb.AppendFormat("{0}:{1}", materialData.Id, TextMapData.GetText(materialData.NameTextMapHash.ToString())).AppendLine();
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var materialData in itemTypes)
|
||||
sb.AppendFormat("{0}:{1}", materialData.Id, TextMapData.GetText(materialData.NameTextMapHash.ToString())).AppendLine();
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
sb.Append("// ").AppendLine(ItemType.ITEM_FURNITURE.ToTranslatedString(language.Key));
|
||||
foreach (var value in HomeWorldFurnitureData.Values)
|
||||
sb.AppendFormat("{0}:{1}", value.Id, TextMapData.GetText(value.NameTextMapHash.ToString())).AppendLine();
|
||||
|
||||
File.WriteAllText(Path.Combine(dir, "Item.txt"), sb.ToString(), Encoding.UTF8);
|
||||
|
||||
#endregion Item
|
||||
|
||||
#region Monsters
|
||||
|
||||
// Monsters
|
||||
sb.Clear();
|
||||
foreach (var monsterType in MonsterData.Values.OrderBy(it => it.Id)
|
||||
.GroupBy(it => it.Type)
|
||||
.OrderBy(it => it.Key))
|
||||
{
|
||||
sb.Append("// ").AppendLine(monsterType.Key.ToTranslatedString(language.Key));
|
||||
foreach (var monsterData in monsterType)
|
||||
{
|
||||
if (TextMapData.TryGetText(monsterData.NameTextMapHash.ToString(), out var text))
|
||||
{
|
||||
sb.AppendFormat("{0}:{1}", monsterData.Id, text);
|
||||
}
|
||||
else
|
||||
{
|
||||
var name = GameData.Monsters[monsterData.Id];
|
||||
if (name == ItemMap.EmptyName)
|
||||
sb.AppendFormat("{0}:{1} - {2}", monsterData.Id, monsterData.MonsterName, text);
|
||||
else
|
||||
sb.AppendFormat("{0}:{1}", monsterData.Id, name);
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
File.WriteAllText(
|
||||
Path.Combine(dir, "Monsters.txt"),
|
||||
sb.ToString(),
|
||||
Encoding.UTF8);
|
||||
|
||||
#endregion Monsters
|
||||
|
||||
#region Quest
|
||||
|
||||
// Quest
|
||||
sb.Clear();
|
||||
foreach (var it in QuestData.Values.OrderBy(it => it.Id))
|
||||
{
|
||||
var name = GameData.Quests[it.Id];
|
||||
if (name == ItemMap.EmptyName)
|
||||
{
|
||||
sb.AppendFormat("{0}:{1} - {2}",
|
||||
it.Id,
|
||||
TextMapData.GetText(MainQuestData[it.MainId].TitleTextMapHash.ToString()),
|
||||
TextMapData.GetText(it.DescTextMapHash.ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendFormat("{0}:{1}", it.Id, name);
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
File.WriteAllText(
|
||||
Path.Combine(dir, "Quest.txt"),
|
||||
sb.ToString(),
|
||||
Encoding.UTF8);
|
||||
|
||||
#endregion Quest
|
||||
|
||||
#region Scene
|
||||
|
||||
// Scene
|
||||
sb.Clear();
|
||||
foreach (var it in DungeonData.Values)
|
||||
{
|
||||
var scene = SceneData[it.SceneId];
|
||||
scene.NameTextMapHash = it.NameTextMapHash;
|
||||
}
|
||||
foreach (var it in SceneData.Values.OrderBy(it => it.Id))
|
||||
{
|
||||
if (it.NameTextMapHash == 0 || !TextMapData.TryGetText(it.NameTextMapHash.ToString(), out var name))
|
||||
{
|
||||
name = GameData.Scenes[it.Id];
|
||||
if (name == ItemMap.EmptyName)
|
||||
name = it.ScriptData;
|
||||
}
|
||||
sb.AppendLine($"{it.Id}:{name}");
|
||||
}
|
||||
File.WriteAllText(
|
||||
Path.Combine(dir, "Scene.txt"),
|
||||
sb.ToString(),
|
||||
Encoding.UTF8);
|
||||
|
||||
#endregion Scene
|
||||
|
||||
#region CutScene
|
||||
|
||||
// CutScene
|
||||
File.WriteAllLines(
|
||||
Path.Combine(dir, "Cutscene.txt"),
|
||||
CutSceneData.Select(it =>
|
||||
{
|
||||
var text = GameData.CutScenes[it.Id];
|
||||
return text == ItemMap.EmptyName
|
||||
? $"{it.Id}:{it.Path.Substring(it.Path.IndexOf('/') + 1)}"
|
||||
: $"{it.Id}:{text}";
|
||||
}), Encoding.UTF8);
|
||||
|
||||
#endregion CutScene
|
||||
|
||||
#region Weapon
|
||||
|
||||
// Weapon
|
||||
File.WriteAllLines(
|
||||
Path.Combine(dir, "Weapon.txt"),
|
||||
WeaponData.Values.Select(it => $"{it.Id}:{TextMapData.GetText(it.NameTextMapHash.ToString())}"),
|
||||
Encoding.UTF8);
|
||||
|
||||
#endregion Weapon
|
||||
}
|
||||
|
||||
#region SceneTag
|
||||
|
||||
// SceneTag
|
||||
|
||||
sb.Clear();
|
||||
|
||||
foreach (var scene in SceneTagData
|
||||
.GroupBy(it => it.SceneId))
|
||||
{
|
||||
sb.Append("// ").AppendLine(scene.Key.ToString());
|
||||
foreach (var sceneTag in scene)
|
||||
{
|
||||
sb.Append($"{sceneTag.Id}:{sceneTag.SceneTagName}");
|
||||
if (sceneTag.IsDefaultValid)
|
||||
sb.Append(" (Default)");
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
File.WriteAllText(
|
||||
Path.Combine(projectResourcesDir, "SceneTag.txt"),
|
||||
sb.ToString(),
|
||||
Encoding.UTF8);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Weather
|
||||
|
||||
// Weather
|
||||
|
||||
sb.Clear();
|
||||
|
||||
foreach (var scene in WeatherData
|
||||
.GroupBy(it => it.SceneId)
|
||||
.OrderBy(it => it.Key))
|
||||
{
|
||||
sb.Append("// ").AppendLine(scene.Key.ToString());
|
||||
foreach (var weather in scene)
|
||||
{
|
||||
var profileName = weather.ProfileName.Substring(weather.ProfileName.LastIndexOf('/') + 1)
|
||||
.Replace("ESP_", "");
|
||||
sb.AppendLine($"{weather.AreaId}:{profileName}");
|
||||
}
|
||||
}
|
||||
File.WriteAllText(
|
||||
Path.Combine(projectResourcesDir, "Weather.txt"),
|
||||
sb.ToString(),
|
||||
Encoding.UTF8);
|
||||
|
||||
#endregion
|
||||
|
||||
File.WriteAllLines(
|
||||
Path.Combine(projectResourcesDir, "AvatarColor.txt"),
|
||||
AvatarData.Values.Select(it => $"{it.Id % 1000 + 1000}:{(int)it.QualityType}"),
|
||||
Encoding.UTF8);
|
||||
|
||||
File.WriteAllLines(
|
||||
Path.Combine(projectResourcesDir, "WeaponColor.txt"),
|
||||
WeaponData.Values.Select(it => $"{it.Id}:{(it.RankLevel >= 5 ? "yellow" : it.RankLevel >= 4 ? "purple" : "blue")}"),
|
||||
Encoding.UTF8);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.CurrentThread.CurrentUICulture = currentCultureInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
Source/GrasscutterTools/Game/Data/ResourceTypeAttribute.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using System;
|
||||
|
||||
namespace GrasscutterTools.Game.Data
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||
internal class ResourceTypeAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public ResourceTypeAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
@@ -28,7 +28,7 @@ namespace GrasscutterTools.Game.Gacha
|
||||
/// 使用这个只需替换掉你原来的的data/banner.json文件,
|
||||
/// 然后重启服务器和客户端,即可享受全卡池抽卡,卡池的选择方式是点击左右箭头进行切换
|
||||
/// </summary>
|
||||
public class GachaBanner
|
||||
internal class GachaBanner
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加卡池请从400开始增加id数值进行添加,这个id需要每个池子不一样,
|
||||
|
@@ -25,7 +25,7 @@ namespace GrasscutterTools.Game.Gacha
|
||||
/// <summary>
|
||||
/// https://github.com/Grasscutters/Grasscutter/pull/639
|
||||
/// </summary>
|
||||
public class GachaBanner2
|
||||
internal class GachaBanner2
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加卡池请从400开始增加id数值进行添加,这个id需要每个池子不一样,
|
||||
|
@@ -28,7 +28,7 @@ namespace GrasscutterTools.Game.Gacha
|
||||
/// <summary>
|
||||
/// https://github.com/Grasscutters/Grasscutter/pull/639
|
||||
/// </summary>
|
||||
public class GachaBanner3
|
||||
internal class GachaBanner3
|
||||
{
|
||||
/// <summary>
|
||||
/// 备注
|
||||
|
@@ -22,7 +22,7 @@ using System.Text;
|
||||
|
||||
namespace GrasscutterTools.Game
|
||||
{
|
||||
public class GameCommand
|
||||
internal class GameCommand
|
||||
{
|
||||
public GameCommand(string name, string command)
|
||||
{
|
||||
|
@@ -17,6 +17,7 @@
|
||||
*
|
||||
**/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using GrasscutterTools.Properties;
|
||||
|
||||
namespace GrasscutterTools.Game
|
||||
@@ -38,13 +39,30 @@ namespace GrasscutterTools.Game
|
||||
Monsters = new ItemMapGroup(Resources.Monsters);
|
||||
Gadgets = new ItemMapGroup(Resources.Gadget);
|
||||
Scenes = new ItemMap(Resources.Scene);
|
||||
SceneTags = new ItemMapGroup(Resources.SceneTag);
|
||||
Dungeons = new ItemMap(Resources.Dungeon);
|
||||
Weapons = new ItemMap(Resources.Weapon);
|
||||
WeaponColors = new ItemMap(Resources.WeaponColor);
|
||||
GachaBannerPrefabs = new ItemMap(Resources.GachaBennerPrefab);
|
||||
GachaBannerTitles = new ItemMap(Resources.GachaBannerTitle);
|
||||
GachaBannerPrefabs = ToDictionary(Resources.GachaBannerPrefab);
|
||||
GachaBannerTitles = ToDictionary(Resources.GachaBannerTitle);
|
||||
Quests = new ItemMap(Resources.Quest);
|
||||
ShopType = new ItemMap(Resources.ShopType);
|
||||
Weathers = new ItemMapGroup(Resources.Weather);
|
||||
}
|
||||
|
||||
private static List<KeyValuePair<string, string>> ToDictionary(string file)
|
||||
{
|
||||
var lines = file.Split('\n');
|
||||
var dic = new List<KeyValuePair<string, string>>(lines.Length);
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var i = line.IndexOf(':');
|
||||
if (i <= 0) continue;
|
||||
var key = line.Substring(0, i).Trim();
|
||||
var value = line.Substring(i + 1).Trim();
|
||||
dic.Add(new KeyValuePair<string, string>(key, value));
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
|
||||
public static ItemMap Achievements { get; private set; }
|
||||
@@ -73,18 +91,22 @@ namespace GrasscutterTools.Game
|
||||
|
||||
public static ItemMap Scenes { get; private set; }
|
||||
|
||||
public static ItemMapGroup SceneTags { get; private set; }
|
||||
|
||||
public static ItemMap Dungeons { get; private set; }
|
||||
|
||||
public static ItemMap Weapons { get; private set; }
|
||||
|
||||
public static ItemMap WeaponColors { get; private set; }
|
||||
|
||||
public static ItemMap GachaBannerPrefabs { get; private set; }
|
||||
public static List<KeyValuePair<string, string>> GachaBannerPrefabs { get; private set; }
|
||||
|
||||
public static ItemMap GachaBannerTitles { get; private set; }
|
||||
public static List<KeyValuePair<string, string>> GachaBannerTitles { get; private set; }
|
||||
|
||||
public static ItemMap Quests { get; private set; }
|
||||
|
||||
public static ItemMap ShopType { get; private set; }
|
||||
|
||||
public static ItemMapGroup Weathers { get; private set; }
|
||||
}
|
||||
}
|
48
Source/GrasscutterTools/Game/Inventory/ItemType.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GrasscutterTools.Game.Inventory
|
||||
{
|
||||
internal enum ItemType
|
||||
{
|
||||
ITEM_NONE = 0,
|
||||
ITEM_VIRTUAL = 1,
|
||||
ITEM_MATERIAL = 2,
|
||||
ITEM_RELIQUARY = 3,
|
||||
ITEM_WEAPON = 4,
|
||||
ITEM_DISPLAY = 5,
|
||||
ITEM_FURNITURE = 6,
|
||||
}
|
||||
|
||||
|
||||
internal static class ItemTypeExtension
|
||||
{
|
||||
private static readonly Dictionary<ItemType, string> TextMapCHS = new Dictionary<ItemType, string>
|
||||
{
|
||||
[ItemType.ITEM_NONE] = "未分类",
|
||||
[ItemType.ITEM_VIRTUAL] = "虚拟道具",
|
||||
[ItemType.ITEM_MATERIAL] = "材料",
|
||||
[ItemType.ITEM_RELIQUARY] = "圣遗物",
|
||||
[ItemType.ITEM_WEAPON] = "物品",
|
||||
[ItemType.ITEM_DISPLAY] = "任务",
|
||||
[ItemType.ITEM_FURNITURE] = "尘歌壶摆设",
|
||||
};
|
||||
private static readonly Dictionary<ItemType, string> TextMapEN = new Dictionary<ItemType, string>
|
||||
{
|
||||
[ItemType.ITEM_NONE] = "None",
|
||||
[ItemType.ITEM_VIRTUAL] = "Virtual",
|
||||
[ItemType.ITEM_MATERIAL] = "Material",
|
||||
[ItemType.ITEM_RELIQUARY] = "Reliquary",
|
||||
[ItemType.ITEM_WEAPON] = "Weapon",
|
||||
[ItemType.ITEM_DISPLAY] = "Display",
|
||||
[ItemType.ITEM_FURNITURE] = "Furniture",
|
||||
};
|
||||
|
||||
public static string ToTranslatedString(this ItemType materialType, string language)
|
||||
{
|
||||
return language.StartsWith("zh") ? TextMapCHS[materialType] : TextMapEN[materialType];
|
||||
}
|
||||
}
|
||||
}
|
224
Source/GrasscutterTools/Game/Inventory/MaterialType.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
// ReSharper disable IdentifierTypo
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GrasscutterTools.Game.Inventory
|
||||
{
|
||||
/// <summary>
|
||||
/// 材料类型
|
||||
/// </summary>
|
||||
internal enum MaterialType
|
||||
{
|
||||
MATERIAL_NONE,
|
||||
MATERIAL_FOOD,
|
||||
MATERIAL_QUEST,
|
||||
MATERIAL_EXCHANGE,
|
||||
MATERIAL_CONSUME,
|
||||
MATERIAL_EXP_FRUIT,
|
||||
MATERIAL_AVATAR,
|
||||
MATERIAL_ADSORBATE,
|
||||
MATERIAL_CRICKET,
|
||||
MATERIAL_ELEM_CRYSTAL,
|
||||
MATERIAL_WEAPON_EXP_STONE,
|
||||
MATERIAL_CHEST,
|
||||
MATERIAL_RELIQUARY_MATERIAL,
|
||||
MATERIAL_AVATAR_MATERIAL,
|
||||
MATERIAL_NOTICE_ADD_HP,
|
||||
MATERIAL_SEA_LAMP,
|
||||
MATERIAL_SELECTABLE_CHEST,
|
||||
MATERIAL_FLYCLOAK,
|
||||
MATERIAL_NAMECARD,
|
||||
MATERIAL_TALENT,
|
||||
MATERIAL_WIDGET,
|
||||
MATERIAL_CHEST_BATCH_USE,
|
||||
MATERIAL_FAKE_ABSORBATE,
|
||||
MATERIAL_CONSUME_BATCH_USE,
|
||||
MATERIAL_WOOD,
|
||||
MATERIAL_FURNITURE_FORMULA,
|
||||
MATERIAL_CHANNELLER_SLAB_BUFF,
|
||||
MATERIAL_FURNITURE_SUITE_FORMULA,
|
||||
MATERIAL_COSTUME,
|
||||
MATERIAL_HOME_SEED,
|
||||
MATERIAL_FISH_BAIT,
|
||||
MATERIAL_FISH_ROD,
|
||||
MATERIAL_SUMO_BUFF, // sumo 活动道具,never appear
|
||||
MATERIAL_FIREWORKS,
|
||||
MATERIAL_BGM,
|
||||
MATERIAL_SPICE_FOOD,
|
||||
MATERIAL_ACTIVITY_ROBOT,
|
||||
MATERIAL_ACTIVITY_GEAR,
|
||||
MATERIAL_ACTIVITY_JIGSAW,
|
||||
MATERIAL_ARANARA,
|
||||
MATERIAL_GCG_CARD,
|
||||
MATERIAL_GCG_CARD_FACE, // 影幻卡面
|
||||
MATERIAL_GCG_CARD_BACK,
|
||||
MATERIAL_GCG_FIELD,
|
||||
MATERIAL_DESHRET_MANUAL,
|
||||
MATERIAL_RENAME_ITEM,
|
||||
MATERIAL_GCG_EXCHANGE_ITEM,
|
||||
MATERIAL_QUEST_EVENT_BOOK,
|
||||
MATERIAL_PROFILE_PICTURE,
|
||||
MATERIAL_RAINBOW_PRINCE_HAND_BOOK,
|
||||
MATERIAL_PHOTO_DISPLAY_BOOK,
|
||||
MATERIAL_REMUS_MUSIC_BOX,
|
||||
MATERIAL_GREATEFESTIVALV2_INVITE,
|
||||
MATERIAL_PHOTOGRAPH_POSE,
|
||||
MATERIAL_FIRE_MASTER_AVATAR_TALENT_ITEM,
|
||||
MATERIAL_PHOTOV5_HAND_BOOK,
|
||||
MATERIAL_AVATAR_TRACE,
|
||||
MATERIAL_CHEST_BATCH_USE_WITH_GROUP,
|
||||
MATERIAL_NATLAN_RELATION_A,
|
||||
MATERIAL_NATLAN_RELATION_B,
|
||||
MATERIAL_LANV5_PAIMON_GREETING_CARD,
|
||||
MATERIAL_NATLAN_RACE_ALBUM,
|
||||
MATERIAL_NATLAN_RACE_ENVELOPE,
|
||||
MATERIAL_MUSIC_GAME_BOOK_THEME,
|
||||
}
|
||||
|
||||
internal static class MaterialTypeExtension
|
||||
{
|
||||
private static readonly Dictionary<MaterialType, string> TextMapCHS = new Dictionary<MaterialType, string>
|
||||
{
|
||||
[MaterialType.MATERIAL_NONE] = "空",
|
||||
[MaterialType.MATERIAL_FOOD] = "食物",
|
||||
[MaterialType.MATERIAL_QUEST] = "任务",
|
||||
[MaterialType.MATERIAL_EXCHANGE] = "收集物",
|
||||
[MaterialType.MATERIAL_CONSUME] = "消耗品",
|
||||
[MaterialType.MATERIAL_EXP_FRUIT] = "经验书",
|
||||
[MaterialType.MATERIAL_AVATAR] = "角色",
|
||||
[MaterialType.MATERIAL_ADSORBATE] = "能量球",
|
||||
[MaterialType.MATERIAL_CRICKET] = "蛐蛐",
|
||||
[MaterialType.MATERIAL_ELEM_CRYSTAL] = "神瞳",
|
||||
[MaterialType.MATERIAL_WEAPON_EXP_STONE] = "武器锻造矿",
|
||||
[MaterialType.MATERIAL_CHEST] = "宝箱",
|
||||
[MaterialType.MATERIAL_RELIQUARY_MATERIAL] = "圣遗物经验瓶",
|
||||
[MaterialType.MATERIAL_AVATAR_MATERIAL] = "角色天赋材料",
|
||||
[MaterialType.MATERIAL_NOTICE_ADD_HP] = "回血食物",
|
||||
[MaterialType.MATERIAL_SEA_LAMP] = "海灯节",
|
||||
[MaterialType.MATERIAL_SELECTABLE_CHEST] = "自选礼包",
|
||||
[MaterialType.MATERIAL_FLYCLOAK] = "风之翼",
|
||||
[MaterialType.MATERIAL_NAMECARD] = "名片卡",
|
||||
[MaterialType.MATERIAL_TALENT] = "天赋材料",
|
||||
[MaterialType.MATERIAL_WIDGET] = "装饰物",
|
||||
[MaterialType.MATERIAL_CHEST_BATCH_USE] = "礼包",
|
||||
[MaterialType.MATERIAL_FAKE_ABSORBATE] = "MATERIAL_FAKE_ABSORBATE",
|
||||
[MaterialType.MATERIAL_CONSUME_BATCH_USE] = "树脂",
|
||||
[MaterialType.MATERIAL_WOOD] = "树木",
|
||||
[MaterialType.MATERIAL_FURNITURE_FORMULA] = "尘歌壶室内摆设",
|
||||
[MaterialType.MATERIAL_CHANNELLER_SLAB_BUFF] = "增益Buff",
|
||||
[MaterialType.MATERIAL_FURNITURE_SUITE_FORMULA] = "尘歌壶摆设套装",
|
||||
[MaterialType.MATERIAL_COSTUME] = "皮肤",
|
||||
[MaterialType.MATERIAL_HOME_SEED] = "种子",
|
||||
[MaterialType.MATERIAL_FISH_BAIT] = "鱼饵",
|
||||
[MaterialType.MATERIAL_FISH_ROD] = "鱼竿",
|
||||
[MaterialType.MATERIAL_SUMO_BUFF] = "MATERIAL_SUMO_BUFF",
|
||||
[MaterialType.MATERIAL_FIREWORKS] = "烟花",
|
||||
[MaterialType.MATERIAL_BGM] = "旋曜玉帛",
|
||||
[MaterialType.MATERIAL_SPICE_FOOD] = "香气四溢的食物",
|
||||
[MaterialType.MATERIAL_ACTIVITY_ROBOT] = "活动-兑换券",
|
||||
[MaterialType.MATERIAL_ACTIVITY_GEAR] = "活动-齿轮",
|
||||
[MaterialType.MATERIAL_ACTIVITY_JIGSAW] = "活动-部件",
|
||||
[MaterialType.MATERIAL_ARANARA] = "兰纳罗",
|
||||
[MaterialType.MATERIAL_GCG_CARD] = "七圣召唤-卡片",
|
||||
[MaterialType.MATERIAL_GCG_CARD_FACE] = "七圣召唤-卡片-正面",
|
||||
[MaterialType.MATERIAL_GCG_CARD_BACK] = "七圣召唤-卡片-背面",
|
||||
[MaterialType.MATERIAL_GCG_FIELD] = "七圣召唤-卡片-场地",
|
||||
[MaterialType.MATERIAL_DESHRET_MANUAL] = "沙漠书",
|
||||
[MaterialType.MATERIAL_RENAME_ITEM] = "改名卡",
|
||||
[MaterialType.MATERIAL_GCG_EXCHANGE_ITEM] = "七圣召唤-特殊卡",
|
||||
[MaterialType.MATERIAL_QUEST_EVENT_BOOK] = "案件记录册",
|
||||
[MaterialType.MATERIAL_PROFILE_PICTURE] = "头像道具",
|
||||
[MaterialType.MATERIAL_RAINBOW_PRINCE_HAND_BOOK] = "特尔克西的奇幻历险",
|
||||
[MaterialType.MATERIAL_PHOTO_DISPLAY_BOOK] = "纪念册",
|
||||
[MaterialType.MATERIAL_REMUS_MUSIC_BOX] = "音乐盒",
|
||||
[MaterialType.MATERIAL_GREATEFESTIVALV2_INVITE] = "邀请函",
|
||||
[MaterialType.MATERIAL_PHOTOGRAPH_POSE] = "照相姿势",
|
||||
[MaterialType.MATERIAL_FIRE_MASTER_AVATAR_TALENT_ITEM] = "燧原矿",
|
||||
[MaterialType.MATERIAL_PHOTOV5_HAND_BOOK] = "回忆相册",
|
||||
[MaterialType.MATERIAL_AVATAR_TRACE] = "游迹",
|
||||
[MaterialType.MATERIAL_CHEST_BATCH_USE_WITH_GROUP] = "分享包",
|
||||
[MaterialType.MATERIAL_NATLAN_RELATION_A] = "圣夜旅织A",
|
||||
[MaterialType.MATERIAL_NATLAN_RELATION_B] = "圣夜旅织B",
|
||||
[MaterialType.MATERIAL_LANV5_PAIMON_GREETING_CARD] = "祝柬",
|
||||
[MaterialType.MATERIAL_NATLAN_RACE_ALBUM] = "砥砺之证",
|
||||
[MaterialType.MATERIAL_NATLAN_RACE_ENVELOPE] = "纪念信件",
|
||||
[MaterialType.MATERIAL_MUSIC_GAME_BOOK_THEME] = "音乐游戏书主题",
|
||||
};
|
||||
private static readonly Dictionary<MaterialType, string> TextMapEN = new Dictionary<MaterialType, string>
|
||||
{
|
||||
[MaterialType.MATERIAL_NONE] = "None",
|
||||
[MaterialType.MATERIAL_FOOD] = "Food",
|
||||
[MaterialType.MATERIAL_QUEST] = "Quest",
|
||||
[MaterialType.MATERIAL_EXCHANGE] = "Exchange",
|
||||
[MaterialType.MATERIAL_CONSUME] = "Consume",
|
||||
[MaterialType.MATERIAL_EXP_FRUIT] = "Exp_fruit",
|
||||
[MaterialType.MATERIAL_AVATAR] = "Avatar",
|
||||
[MaterialType.MATERIAL_ADSORBATE] = "Adsorbate",
|
||||
[MaterialType.MATERIAL_CRICKET] = "Cricket",
|
||||
[MaterialType.MATERIAL_ELEM_CRYSTAL] = "Elem_crystal",
|
||||
[MaterialType.MATERIAL_WEAPON_EXP_STONE] = "Weapon_exp_stone",
|
||||
[MaterialType.MATERIAL_CHEST] = "Chest",
|
||||
[MaterialType.MATERIAL_RELIQUARY_MATERIAL] = "Reliquary_material",
|
||||
[MaterialType.MATERIAL_AVATAR_MATERIAL] = "Avatar_material",
|
||||
[MaterialType.MATERIAL_NOTICE_ADD_HP] = "Notice_add_hp",
|
||||
[MaterialType.MATERIAL_SEA_LAMP] = "Sea_lamp",
|
||||
[MaterialType.MATERIAL_SELECTABLE_CHEST] = "Selectable_chest",
|
||||
[MaterialType.MATERIAL_FLYCLOAK] = "Flycloak",
|
||||
[MaterialType.MATERIAL_NAMECARD] = "Namecard",
|
||||
[MaterialType.MATERIAL_TALENT] = "Talent",
|
||||
[MaterialType.MATERIAL_WIDGET] = "Widget",
|
||||
[MaterialType.MATERIAL_CHEST_BATCH_USE] = "Chest_batch_use",
|
||||
[MaterialType.MATERIAL_FAKE_ABSORBATE] = "Fake_absorbate",
|
||||
[MaterialType.MATERIAL_CONSUME_BATCH_USE] = "Consume_batch_use",
|
||||
[MaterialType.MATERIAL_WOOD] = "Wood",
|
||||
[MaterialType.MATERIAL_FURNITURE_FORMULA] = "Furniture_formula",
|
||||
[MaterialType.MATERIAL_CHANNELLER_SLAB_BUFF] = "Channeller_slab_buff",
|
||||
[MaterialType.MATERIAL_FURNITURE_SUITE_FORMULA] = "Furniture_suite_formula",
|
||||
[MaterialType.MATERIAL_COSTUME] = "Costume",
|
||||
[MaterialType.MATERIAL_HOME_SEED] = "Home_seed",
|
||||
[MaterialType.MATERIAL_FISH_BAIT] = "Fish_bait",
|
||||
[MaterialType.MATERIAL_FISH_ROD] = "Fish_rod",
|
||||
[MaterialType.MATERIAL_SUMO_BUFF] = "Sumo_buff",
|
||||
[MaterialType.MATERIAL_FIREWORKS] = "Fireworks",
|
||||
[MaterialType.MATERIAL_BGM] = "Bgm",
|
||||
[MaterialType.MATERIAL_SPICE_FOOD] = "Spice_food",
|
||||
[MaterialType.MATERIAL_ACTIVITY_ROBOT] = "Activity_robot",
|
||||
[MaterialType.MATERIAL_ACTIVITY_GEAR] = "Activity_gear",
|
||||
[MaterialType.MATERIAL_ACTIVITY_JIGSAW] = "Activity_jigsaw",
|
||||
[MaterialType.MATERIAL_ARANARA] = "Aranara",
|
||||
[MaterialType.MATERIAL_GCG_CARD] = "Gcg_card",
|
||||
[MaterialType.MATERIAL_GCG_CARD_FACE] = "Gcg_card_face",
|
||||
[MaterialType.MATERIAL_GCG_CARD_BACK] = "Gcg_card_back",
|
||||
[MaterialType.MATERIAL_GCG_FIELD] = "Gcg_field",
|
||||
[MaterialType.MATERIAL_DESHRET_MANUAL] = "Deshret_manual",
|
||||
[MaterialType.MATERIAL_RENAME_ITEM] = "Rename_item",
|
||||
[MaterialType.MATERIAL_GCG_EXCHANGE_ITEM] = "Gcg_exchange_item",
|
||||
[MaterialType.MATERIAL_QUEST_EVENT_BOOK] = "Quest_event_book",
|
||||
[MaterialType.MATERIAL_PROFILE_PICTURE] = "Profile_picture",
|
||||
[MaterialType.MATERIAL_RAINBOW_PRINCE_HAND_BOOK] = "Thelxie's Fantastic Adventures",
|
||||
[MaterialType.MATERIAL_PHOTO_DISPLAY_BOOK] = "Album",
|
||||
[MaterialType.MATERIAL_REMUS_MUSIC_BOX] = "MusicBox",
|
||||
[MaterialType.MATERIAL_GREATEFESTIVALV2_INVITE] = "Invitation",
|
||||
[MaterialType.MATERIAL_PHOTOGRAPH_POSE] = "Photograph_pose",
|
||||
[MaterialType.MATERIAL_FIRE_MASTER_AVATAR_TALENT_ITEM] = "Fire_master_avatar_talent_item",
|
||||
[MaterialType.MATERIAL_PHOTOV5_HAND_BOOK] = "Photov5_hand_book",
|
||||
[MaterialType.MATERIAL_AVATAR_TRACE] = "Avatar_trace",
|
||||
[MaterialType.MATERIAL_CHEST_BATCH_USE_WITH_GROUP] = "Chest_batch_use_with_group",
|
||||
[MaterialType.MATERIAL_NATLAN_RELATION_A] = "Natlan_relation_a",
|
||||
[MaterialType.MATERIAL_NATLAN_RELATION_B] = "Natlan_relation_b",
|
||||
[MaterialType.MATERIAL_LANV5_PAIMON_GREETING_CARD] = "Lanv5_paimon_greeting_card",
|
||||
[MaterialType.MATERIAL_NATLAN_RACE_ALBUM] = "Natlan_race_album",
|
||||
[MaterialType.MATERIAL_NATLAN_RACE_ENVELOPE] = "Natlan_race_envelope",
|
||||
[MaterialType.MATERIAL_MUSIC_GAME_BOOK_THEME] = "Music_game_book_theme",
|
||||
};
|
||||
|
||||
public static string ToTranslatedString(this MaterialType materialType, string language)
|
||||
{
|
||||
if (!TextMapCHS.ContainsKey(materialType))
|
||||
return materialType.ToString();
|
||||
return language.StartsWith("zh") ? TextMapCHS[materialType] : TextMapEN[materialType];
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,7 +22,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace GrasscutterTools.Game
|
||||
{
|
||||
public class ItemMap
|
||||
internal class ItemMap
|
||||
{
|
||||
public ItemMap(string idNamePairs)
|
||||
{
|
||||
|
@@ -25,7 +25,7 @@ namespace GrasscutterTools.Game
|
||||
/// <summary>
|
||||
/// ID映射组,Key为分类,双斜杠构造
|
||||
/// </summary>
|
||||
public class ItemMapGroup : Dictionary<string, ItemMap>
|
||||
internal class ItemMapGroup : Dictionary<string, ItemMap>
|
||||
{
|
||||
public ItemMapGroup(string idNamePairs)
|
||||
{
|
||||
@@ -64,8 +64,13 @@ namespace GrasscutterTools.Game
|
||||
/// </summary>
|
||||
public IEnumerable<string> AllLines => Values.SelectMany(it => it.Lines);
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有ID
|
||||
/// </summary>
|
||||
public IEnumerable<int> AllIds => Values.SelectMany(it => it.Ids);
|
||||
|
||||
private string[] lines;
|
||||
public string[] Lines => lines ?? (lines = AllLines.ToArray());
|
||||
public string[] Lines => lines ??= AllLines.ToArray();
|
||||
|
||||
public string this[int id]
|
||||
{
|
||||
|
@@ -27,7 +27,7 @@ namespace GrasscutterTools.Game.Mail
|
||||
/// <summary>
|
||||
/// 邮件
|
||||
/// </summary>
|
||||
public class Mail
|
||||
internal class Mail
|
||||
{
|
||||
/// <summary>
|
||||
/// 发件人
|
||||
|
93
Source/GrasscutterTools/Game/Props/GadgetType.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GrasscutterTools.Game.Props
|
||||
{
|
||||
internal static class GadgetType
|
||||
{
|
||||
private static readonly Dictionary<string, string> TextMapCHS = new Dictionary<string, string>
|
||||
{
|
||||
["Avatar"] = "角色",
|
||||
["Gear"] = "机关装置",
|
||||
["Field"] = "领域",
|
||||
["Bullet"] = "技能/飞弹",
|
||||
["Gadget"] = "Gadget",
|
||||
["AirflowField"] = "气流领域",
|
||||
["SpeedupField"] = "加速领域",
|
||||
["GatherObject"] = "采集物品",
|
||||
["Platform"] = "平台",
|
||||
["AmberWind"] = "风琥珀",
|
||||
["Vehicle"] = "载具",
|
||||
["MonsterEquip"] = "怪物装备",
|
||||
["Equip"] = "装备",
|
||||
["SubEquip"] = "副装备",
|
||||
["FishRod"] = "钓鱼竿",
|
||||
["Grass"] = "草",
|
||||
["Water"] = "水",
|
||||
["Tree"] = "树",
|
||||
["Bush"] = "灌木",
|
||||
["Lightning"] = "闪电",
|
||||
["CustomTile"] = "自定义贴图",
|
||||
["TransPointFirst"] = "传送点1",
|
||||
["TransPointSecond"] = "传送点2",
|
||||
["Chest"] = "宝箱",
|
||||
["GeneralRewardPoint"] = "通用奖励点",
|
||||
["OfferingGadget"] = "祭品Gadget",
|
||||
["Worktop"] = "工作台",
|
||||
["CustomGadget"] = "自定义Gadget",
|
||||
["BlackMud"] = "黑色泥浆",
|
||||
["DeshretObeliskGadget"] = "赤王方尖碑",
|
||||
["JourneyGearOperatorGadget"] = "旅途装备操作Gadget",
|
||||
["QuestGadget"] = "任务Gadget",
|
||||
["RoguelikeOperatorGadget"] = "肉鸽 操作台",
|
||||
["NightCrowGadget"] = "幽邃鸦眼",
|
||||
["MpPlayRewardPoint"] = "多人游戏奖励点",
|
||||
["CurveMoveGadget"] = "曲线移动Gadget",
|
||||
["RewardStatue"] = "地城奖励树",
|
||||
["RewardPoint"] = "循环地城奖励点",
|
||||
["Foundation"] = "底座",
|
||||
["Projector"] = "投影仪",
|
||||
["Screen"] = "屏幕",
|
||||
["CoinCollectLevelGadget"] = "金币收集等级Gadget",
|
||||
["EchoShell"] = "回声海螺",
|
||||
["UgcSpecialGadget"] = "UGC特殊Gadget",
|
||||
["UgcTowerLevelUpGadget"] = "UGC塔升级Gadget",
|
||||
["GatherPoint"] = "采集物挂接点",
|
||||
["MiracleRing"] = "奇迹之环",
|
||||
["EnvAnimal"] = "环境动物",
|
||||
["EnergyBall"] = "能量球",
|
||||
["SealGadget"] = "封印Gadget",
|
||||
["ViewPoint"] = "观景点",
|
||||
["FishPool"] = "钓鱼点",
|
||||
["ElemCrystal"] = "元素水晶",
|
||||
["Deprecated"] = "弃用",
|
||||
["WindSeed"] = "风种子",
|
||||
["UIInteractGadget"] = "界面交互Gadget",
|
||||
["Camera"] = "摄像机",
|
||||
};
|
||||
|
||||
public static string ToTranslatedString(string gadgetType, string language)
|
||||
{
|
||||
if (string.IsNullOrEmpty(gadgetType)) gadgetType = "Deprecated";
|
||||
return language.StartsWith("zh") ? TextMapCHS[gadgetType] : gadgetType;
|
||||
}
|
||||
}
|
||||
}
|
29
Source/GrasscutterTools/Game/Props/ItemUseData.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Props
|
||||
{
|
||||
internal class ItemUseData
|
||||
{
|
||||
[JsonProperty("useParam")]
|
||||
public string[] UseParam { get; set; }
|
||||
}
|
||||
}
|
69
Source/GrasscutterTools/Game/Props/MonsterType.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GrasscutterTools.Game.Props
|
||||
{
|
||||
/// <summary>
|
||||
/// 怪物种类
|
||||
/// </summary>
|
||||
internal enum MonsterType
|
||||
{
|
||||
MONSTER_NONE = 0,
|
||||
MONSTER_ORDINARY = 1,
|
||||
MONSTER_BOSS = 2,
|
||||
MONSTER_ENV_ANIMAL = 3,
|
||||
MONSTER_LITTLE_MONSTER = 4,
|
||||
MONSTER_FISH = 5,
|
||||
MONSTER_PARTNER = 6,
|
||||
}
|
||||
|
||||
internal static class ItemTypeExtension
|
||||
{
|
||||
private static readonly Dictionary<MonsterType, string> TextMapCHS = new Dictionary<MonsterType, string>
|
||||
{
|
||||
[MonsterType.MONSTER_NONE] = "未分类",
|
||||
[MonsterType.MONSTER_ORDINARY] = "普通怪物",
|
||||
[MonsterType.MONSTER_BOSS] = "BOSS",
|
||||
[MonsterType.MONSTER_ENV_ANIMAL] = "动物",
|
||||
[MonsterType.MONSTER_LITTLE_MONSTER] = "小怪",
|
||||
[MonsterType.MONSTER_FISH] = "鱼",
|
||||
[MonsterType.MONSTER_PARTNER] = "友军",
|
||||
};
|
||||
|
||||
private static readonly Dictionary<MonsterType, string> TextMapEN = new Dictionary<MonsterType, string>
|
||||
{
|
||||
[MonsterType.MONSTER_NONE] = "None",
|
||||
[MonsterType.MONSTER_ORDINARY] = "Ordinary",
|
||||
[MonsterType.MONSTER_BOSS] = "Boss",
|
||||
[MonsterType.MONSTER_ENV_ANIMAL] = "Env_animal",
|
||||
[MonsterType.MONSTER_LITTLE_MONSTER] = "Little_monster",
|
||||
[MonsterType.MONSTER_FISH] = "Fish",
|
||||
[MonsterType.MONSTER_PARTNER] = "Partner",
|
||||
};
|
||||
|
||||
public static string ToTranslatedString(this MonsterType materialType, string language)
|
||||
{
|
||||
return language.StartsWith("zh") ? TextMapCHS[materialType] : TextMapEN[materialType];
|
||||
}
|
||||
}
|
||||
}
|
62
Source/GrasscutterTools/Game/Props/QualityType.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace GrasscutterTools.Game.Props
|
||||
{
|
||||
internal enum QualityType
|
||||
{
|
||||
/// <summary>
|
||||
/// 无
|
||||
/// </summary>
|
||||
QUALITY_NONE = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 一星
|
||||
/// </summary>
|
||||
QUALITY_WHITE = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 二星
|
||||
/// </summary>
|
||||
QUALITY_GREEN = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 三星
|
||||
/// </summary>
|
||||
QUALITY_BLUE = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 四星
|
||||
/// </summary>
|
||||
QUALITY_PURPLE = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 五星
|
||||
/// </summary>
|
||||
QUALITY_ORANGE = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 限定五星
|
||||
/// </summary>
|
||||
//QUALITY_ORANGE_SP = 105,
|
||||
QUALITY_ORANGE_SP = 5,
|
||||
}
|
||||
}
|
34
Source/GrasscutterTools/Game/Props/SceneType.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace GrasscutterTools.Game.Props
|
||||
{
|
||||
public enum SceneType
|
||||
{
|
||||
SCENE_NONE = 0,
|
||||
SCENE_WORLD = 1,
|
||||
SCENE_DUNGEON = 2,
|
||||
SCENE_ROOM = 3,
|
||||
SCENE_HOME_WORLD = 4,
|
||||
SCENE_HOME_ROOM = 5,
|
||||
SCENE_ACTIVITY = 6,
|
||||
}
|
||||
}
|
@@ -25,7 +25,7 @@ using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace GrasscutterTools.Game.Shop
|
||||
{
|
||||
public class ShopGoodsData
|
||||
internal class ShopGoodsData
|
||||
{
|
||||
[JsonProperty("goodsId")]
|
||||
public int GoodsId { get; set; }
|
||||
|
@@ -26,7 +26,7 @@ using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace GrasscutterTools.Game.Shop
|
||||
{
|
||||
public class ShopInfo
|
||||
internal class ShopInfo
|
||||
{
|
||||
public ShopInfo()
|
||||
{
|
||||
|
@@ -23,7 +23,7 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game.Shop
|
||||
{
|
||||
public class ShopTable
|
||||
internal class ShopTable
|
||||
{
|
||||
[JsonProperty("shopId")]
|
||||
public int ShopType { get; set; }
|
||||
|
@@ -26,7 +26,7 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Game
|
||||
{
|
||||
public class TextMapData
|
||||
internal class TextMapData
|
||||
{
|
||||
public TextMapData(string resourcesDirPath)
|
||||
{
|
||||
@@ -44,6 +44,8 @@ namespace GrasscutterTools.Game
|
||||
|
||||
private void LoadManualTextMap(string manualTextMapPath)
|
||||
{
|
||||
if (!File.Exists(manualTextMapPath)) return;
|
||||
|
||||
using (var fs = File.OpenRead(manualTextMapPath))
|
||||
using (var sr = new StreamReader(fs))
|
||||
using (var reader = new JsonTextReader(sr))
|
||||
@@ -86,11 +88,30 @@ namespace GrasscutterTools.Game
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(string textMapPath) => TextMap.ContainsKey(textMapPath) || DefaultTextMap.ContainsKey(textMapPath);
|
||||
|
||||
public string GetText(string textMapHash)
|
||||
{
|
||||
return TextMap.TryGetValue(textMapHash, out var text) ? text
|
||||
: DefaultTextMap.TryGetValue(textMapHash, out text) ? text
|
||||
: "???";
|
||||
: DefaultTextMap.TryGetValue(textMapHash, out text) ? "[CHS] - " + text
|
||||
: "[N/A] " + textMapHash;
|
||||
}
|
||||
|
||||
public bool TryGetText(string textMapHash, out string text)
|
||||
{
|
||||
if (TextMap.TryGetValue(textMapHash, out text))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DefaultTextMap.TryGetValue(textMapHash, out text))
|
||||
{
|
||||
text = "[CHS] - " + text;
|
||||
return true;
|
||||
}
|
||||
|
||||
text = "[N/A] " + textMapHash;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -40,6 +40,8 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<LangVersion>11</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -49,6 +51,8 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<LangVersion>11</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>Resources\IconGrasscutter.ico</ApplicationIcon>
|
||||
@@ -87,6 +91,14 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="DispatchServer\DispatchServerAPI.cs" />
|
||||
<Compile Include="DispatchServer\Model\ServerStatus.cs" />
|
||||
<Compile Include="Eavesdrop\Certifier.cs" />
|
||||
<Compile Include="Eavesdrop\Eavesdropper.cs" />
|
||||
<Compile Include="Eavesdrop\Event Args\RequestInterceptedEventArgs.cs" />
|
||||
<Compile Include="Eavesdrop\Event Args\ResponseInterceptedEventArgs.cs" />
|
||||
<Compile Include="Eavesdrop\Interceptors.cs" />
|
||||
<Compile Include="Eavesdrop\Internals\INETOptions.cs" />
|
||||
<Compile Include="Eavesdrop\Internals\NativeMethods.cs" />
|
||||
<Compile Include="Eavesdrop\Network\EavesNode.cs" />
|
||||
<Compile Include="Forms\FormActivityEditor.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -139,6 +151,24 @@
|
||||
<Compile Include="Game\Activity\NewActivityItem.cs" />
|
||||
<Compile Include="Game\CommandVersion.cs" />
|
||||
<Compile Include="Game\CutScene\CutSceneItem.cs" />
|
||||
<Compile Include="Game\Data\Excels\AvatarData.cs" />
|
||||
<Compile Include="Game\Data\Excels\AchievementData.cs" />
|
||||
<Compile Include="Game\Data\Excels\DungeonData.cs" />
|
||||
<Compile Include="Game\Data\Excels\GadgetData.cs" />
|
||||
<Compile Include="Game\Data\Excels\GatherData.cs" />
|
||||
<Compile Include="Game\Data\Excels\HomeWorldBgmData.cs" />
|
||||
<Compile Include="Game\Data\Excels\HomeWorldFurnitureData.cs" />
|
||||
<Compile Include="Game\Data\Excels\MaterialData.cs" />
|
||||
<Compile Include="Game\Data\Excels\MainQuestData.cs" />
|
||||
<Compile Include="Game\Data\Excels\QuestData.cs" />
|
||||
<Compile Include="Game\Data\Excels\ReliquaryData.cs" />
|
||||
<Compile Include="Game\Data\Excels\MonsterData.cs" />
|
||||
<Compile Include="Game\Data\Excels\SceneData.cs" />
|
||||
<Compile Include="Game\Data\Excels\SceneTagData.cs" />
|
||||
<Compile Include="Game\Data\Excels\WeatherData.cs" />
|
||||
<Compile Include="Game\Data\GameResource.cs" />
|
||||
<Compile Include="Game\Data\GameResources.cs" />
|
||||
<Compile Include="Game\Data\ResourceTypeAttribute.cs" />
|
||||
<Compile Include="Game\Drop\DropData.cs" />
|
||||
<Compile Include="Game\Drop\DropInfo.cs" />
|
||||
<Compile Include="Game\Dungeon\DungeonItem.cs" />
|
||||
@@ -148,12 +178,20 @@
|
||||
<Compile Include="Game\Gacha\BannerType.cs" />
|
||||
<Compile Include="Game\Gacha\GachaBanner.cs" />
|
||||
<Compile Include="Game\GameData.cs" />
|
||||
<Compile Include="Game\Inventory\ItemType.cs" />
|
||||
<Compile Include="Game\Inventory\MaterialType.cs" />
|
||||
<Compile Include="Game\Data\Excels\WeaponData.cs" />
|
||||
<Compile Include="Game\ItemMap.cs" />
|
||||
<Compile Include="Game\ItemMapGroup.cs" />
|
||||
<Compile Include="Game\Mail\Mail.cs" />
|
||||
<Compile Include="Game\Mail\MailItem.cs" />
|
||||
<Compile Include="Game\Player\PlayerData.cs" />
|
||||
<Compile Include="Game\Props\GadgetType.cs" />
|
||||
<Compile Include="Game\Props\ItemUseData.cs" />
|
||||
<Compile Include="Game\Props\MonsterType.cs" />
|
||||
<Compile Include="Game\Props\PlayerProperty.cs" />
|
||||
<Compile Include="Game\Props\QualityType.cs" />
|
||||
<Compile Include="Game\Props\SceneType.cs" />
|
||||
<Compile Include="Game\SetStatsCommand.cs" />
|
||||
<Compile Include="Game\Shop\ItemParamData.cs" />
|
||||
<Compile Include="Game\Shop\ShopGoodsData.cs" />
|
||||
@@ -243,6 +281,12 @@
|
||||
<Compile Include="Pages\PageOpenCommand.Designer.cs">
|
||||
<DependentUpon>PageOpenCommand.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageProxy.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageProxy.Designer.cs">
|
||||
<DependentUpon>PageProxy.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageQuest.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
@@ -255,12 +299,24 @@
|
||||
<Compile Include="Pages\PageScene.Designer.cs">
|
||||
<DependentUpon>PageScene.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageSceneTag.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageSceneTag.Designer.cs">
|
||||
<DependentUpon>PageSceneTag.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageSetProp.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageSetProp.Designer.cs">
|
||||
<DependentUpon>PageSetProp.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageSettings.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageSettings.Designer.cs">
|
||||
<DependentUpon>PageSettings.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageSpawn.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
@@ -279,6 +335,12 @@
|
||||
<Compile Include="Pages\PageTools.Designer.cs">
|
||||
<DependentUpon>PageTools.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageWeather.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageWeather.Designer.cs">
|
||||
<DependentUpon>PageWeather.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\Resources.zh-TW.Designer.cs">
|
||||
@@ -290,11 +352,14 @@
|
||||
<Compile Include="Utils\ArtifactUtils.cs" />
|
||||
<Compile Include="Utils\Common.cs" />
|
||||
<Compile Include="Utils\GuiRedirect.cs" />
|
||||
<Compile Include="Utils\HighDPIUtil.cs" />
|
||||
<Compile Include="Utils\KeyGo.cs" />
|
||||
<Compile Include="Utils\HotKeyItem.cs" />
|
||||
<Compile Include="Utils\HttpHelper.cs" />
|
||||
<Compile Include="Utils\Logger.cs" />
|
||||
<Compile Include="Utils\GithubHelper.cs" />
|
||||
<Compile Include="Utils\ProxyHelper.cs" />
|
||||
<Compile Include="Utils\SparseSet.cs" />
|
||||
<Compile Include="Utils\ToggleParser.cs" />
|
||||
<Compile Include="Utils\UIUtil.cs" />
|
||||
<EmbeddedResource Include="Forms\FormActivityEditor.en-US.resx">
|
||||
@@ -464,6 +529,7 @@
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageGiveItem.resx">
|
||||
<DependentUpon>PageGiveItem.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageGiveItem.ru-RU.resx">
|
||||
<DependentUpon>PageGiveItem.cs</DependentUpon>
|
||||
@@ -544,6 +610,18 @@
|
||||
<EmbeddedResource Include="Pages\PageOpenCommand.zh-TW.resx">
|
||||
<DependentUpon>PageOpenCommand.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageProxy.en-US.resx">
|
||||
<DependentUpon>PageProxy.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageProxy.resx">
|
||||
<DependentUpon>PageProxy.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageProxy.ru-RU.resx">
|
||||
<DependentUpon>PageProxy.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageProxy.zh-TW.resx">
|
||||
<DependentUpon>PageProxy.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageQuest.en-US.resx">
|
||||
<DependentUpon>PageQuest.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
@@ -568,6 +646,18 @@
|
||||
<EmbeddedResource Include="Pages\PageScene.zh-TW.resx">
|
||||
<DependentUpon>PageScene.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSceneTag.en-US.resx">
|
||||
<DependentUpon>PageSceneTag.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSceneTag.resx">
|
||||
<DependentUpon>PageSceneTag.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSceneTag.ru-RU.resx">
|
||||
<DependentUpon>PageSceneTag.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSceneTag.zh-TW.resx">
|
||||
<DependentUpon>PageSceneTag.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSetProp.en-US.resx">
|
||||
<DependentUpon>PageSetProp.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
@@ -580,11 +670,24 @@
|
||||
<EmbeddedResource Include="Pages\PageSetProp.zh-TW.resx">
|
||||
<DependentUpon>PageSetProp.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSettings.en-US.resx">
|
||||
<DependentUpon>PageSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSettings.resx">
|
||||
<DependentUpon>PageSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSettings.ru-RU.resx">
|
||||
<DependentUpon>PageSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSettings.zh-TW.resx">
|
||||
<DependentUpon>PageSettings.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSpawn.en-US.resx">
|
||||
<DependentUpon>PageSpawn.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSpawn.resx">
|
||||
<DependentUpon>PageSpawn.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageSpawn.ru-RU.resx">
|
||||
<DependentUpon>PageSpawn.cs</DependentUpon>
|
||||
@@ -607,6 +710,18 @@
|
||||
<EmbeddedResource Include="Pages\PageTools.resx">
|
||||
<DependentUpon>PageTools.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageWeather.en-US.resx">
|
||||
<DependentUpon>PageWeather.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageWeather.resx">
|
||||
<DependentUpon>PageWeather.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageWeather.ru-RU.resx">
|
||||
<DependentUpon>PageWeather.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageWeather.zh-TW.resx">
|
||||
<DependentUpon>PageWeather.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.zh-TW.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.zh-TW.Designer.cs</LastGenOutput>
|
||||
@@ -642,6 +757,8 @@
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<None Include="Eavesdrop\LICENSE.md" />
|
||||
<None Include="GrasscutterTools.licenseheader" />
|
||||
<None Include="GrasscutterTools.snk" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
@@ -671,8 +788,8 @@
|
||||
<Content Include="Resources\en-us\CustomCommands.txt" />
|
||||
<None Include="Resources\en-us\Dungeon.txt" />
|
||||
<Content Include="Resources\en-us\Cutscene.txt" />
|
||||
<Content Include="Resources\en-us\GachaBennerTitle.txt" />
|
||||
<Content Include="Resources\en-us\GachaBennerPrefab.txt" />
|
||||
<Content Include="Resources\en-us\GachaBannerTitle.txt" />
|
||||
<Content Include="Resources\en-us\GachaBannerPrefab.txt" />
|
||||
<Content Include="Resources\en-us\Gadget.txt" />
|
||||
<Content Include="Resources\en-us\Item.txt" />
|
||||
<Content Include="Resources\en-us\Monsters.txt" />
|
||||
@@ -682,6 +799,7 @@
|
||||
<Content Include="Resources\en-us\ShopType.txt" />
|
||||
<Content Include="Resources\en-us\Weapon.txt" />
|
||||
<None Include="Resources\Newtonsoft.Json.dll" />
|
||||
<Content Include="Resources\en-us\Weather.txt" />
|
||||
<Content Include="Resources\MyTools.java" />
|
||||
<Content Include="Resources\ru-ru\Achievement.txt" />
|
||||
<Content Include="Resources\ru-ru\Activity.txt" />
|
||||
@@ -693,8 +811,8 @@
|
||||
<Content Include="Resources\ru-ru\CustomCommands.txt" />
|
||||
<None Include="Resources\ru-ru\Dungeon.txt" />
|
||||
<Content Include="Resources\ru-ru\Cutscene.txt" />
|
||||
<Content Include="Resources\ru-ru\GachaBennerTitle.txt" />
|
||||
<Content Include="Resources\ru-ru\GachaBennerPrefab.txt" />
|
||||
<Content Include="Resources\ru-ru\GachaBannerTitle.txt" />
|
||||
<Content Include="Resources\ru-ru\GachaBannerPrefab.txt" />
|
||||
<Content Include="Resources\ru-ru\Gadget.txt" />
|
||||
<Content Include="Resources\ru-ru\Item.txt" />
|
||||
<Content Include="Resources\ru-ru\Monsters.txt" />
|
||||
@@ -707,7 +825,9 @@
|
||||
<Content Include="Resources\IconGrasscutter.png" />
|
||||
<None Include="Resources\ImgSupport.png" />
|
||||
<Content Include="Resources\Permissions.txt" />
|
||||
<Content Include="Resources\SceneTag.txt" />
|
||||
<Content Include="Resources\WeaponColor.txt" />
|
||||
<Content Include="Resources\zh-cn\Weather.txt" />
|
||||
<Content Include="Resources\zh-cn\Achievement.txt" />
|
||||
<Content Include="Resources\zh-cn\Activity.txt" />
|
||||
<Content Include="Resources\zh-cn\ArtifactCat.txt" />
|
||||
@@ -720,7 +840,7 @@
|
||||
<None Include="Resources\zh-cn\Dungeon.txt" />
|
||||
<Content Include="Resources\zh-cn\Cutscene.txt" />
|
||||
<Content Include="Resources\zh-cn\GachaBannerTitle.txt" />
|
||||
<Content Include="Resources\zh-cn\GachaBennerPrefab.txt" />
|
||||
<Content Include="Resources\zh-cn\GachaBannerPrefab.txt" />
|
||||
<Content Include="Resources\zh-cn\Gadget.txt" />
|
||||
<Content Include="Resources\zh-cn\Item.txt" />
|
||||
<Content Include="Resources\zh-cn\Monsters.txt" />
|
||||
@@ -739,8 +859,9 @@
|
||||
<Content Include="Resources\zh-tw\CustomCommands.txt" />
|
||||
<None Include="Resources\zh-tw\Dungeon.txt" />
|
||||
<Content Include="Resources\zh-tw\Cutscene.txt" />
|
||||
<Content Include="Resources\zh-tw\GachaBennerTitle.txt" />
|
||||
<Content Include="Resources\zh-tw\GachaBennerPrefab.txt" />
|
||||
<Content Include="Resources\zh-tw\GachaBannerTitle.txt" />
|
||||
<Content Include="Resources\zh-tw\GachaBannerPrefab.txt" />
|
||||
<None Include="Resources\zh-tw\Gadget.txt" />
|
||||
<Content Include="Resources\zh-tw\Item.txt" />
|
||||
<Content Include="Resources\zh-tw\Monsters.txt" />
|
||||
<Content Include="Resources\zh-tw\PlayerProperty.txt" />
|
||||
|
19
Source/GrasscutterTools/GrasscutterTools.licenseheader
Normal file
@@ -0,0 +1,19 @@
|
||||
extensions: .cs
|
||||
/**
|
||||
* Grasscutter Tools
|
||||
* Copyright (C) 2023 jie65535
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**/
|
@@ -26,7 +26,7 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.OpenCommand
|
||||
{
|
||||
public class OpenCommandAPI
|
||||
internal class OpenCommandAPI
|
||||
{
|
||||
public OpenCommandAPI(string host, string token = "")
|
||||
{
|
||||
@@ -44,11 +44,28 @@ namespace GrasscutterTools.OpenCommand
|
||||
|
||||
public bool CanInvoke { get; private set; }
|
||||
|
||||
private Version version = new Version(1, 6, 1);
|
||||
|
||||
public Version Version
|
||||
{
|
||||
get => version;
|
||||
private set
|
||||
{
|
||||
version = value;
|
||||
CanInvokeMultipleCmd = version >= new Version(1, 7);
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanInvokeMultipleCmd { get; private set; }
|
||||
|
||||
public async Task<bool> Ping()
|
||||
{
|
||||
//try
|
||||
//{
|
||||
var response = await DoRequest("ping");
|
||||
if (response.Data is string str && Version.TryParse(str, out var version))
|
||||
Version = version;
|
||||
|
||||
return response.RetCode == 200;
|
||||
//}
|
||||
//catch (Exception)
|
||||
|
@@ -18,13 +18,15 @@
|
||||
**/
|
||||
|
||||
using System.Windows.Forms;
|
||||
|
||||
using GrasscutterTools.Properties;
|
||||
using GrasscutterTools.Utils;
|
||||
|
||||
namespace GrasscutterTools.Pages
|
||||
{
|
||||
internal partial class PageAbout : BasePage
|
||||
{
|
||||
public override string Text => Resources.PageAboutTitle;
|
||||
|
||||
public PageAbout()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
@@ -126,10 +126,10 @@
|
||||
<data name=">>LblSupportDescription.Parent" xml:space="preserve">
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="LnkGithub.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Bottom, Left</value>
|
||||
<data name=">>LblSupportDescription.Name" xml:space="preserve">
|
||||
<value>LblSupportDescription</value>
|
||||
</data>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="LnkOpenChat.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Bottom</value>
|
||||
</data>
|
||||
@@ -149,16 +149,10 @@
|
||||
<data name=">>LnkGithub.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.LinkLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="LnkOpenChat.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleCenter</value>
|
||||
</data>
|
||||
<data name="LblSupportDescription.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>7, 17</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="GrasscutterToolsSupport.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>498, 86</value>
|
||||
</data>
|
||||
@@ -194,13 +188,19 @@
|
||||
<value>$this</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>GrasscutterTools.Pages.BasePage, GrasscutterTools, Version=1.8.1.0, Culture=neutral, PublicKeyToken=de2b1c089621e923</value>
|
||||
<value>GrasscutterTools.Pages.BasePage, GrasscutterTools, Version=1.13.0.0, Culture=neutral, PublicKeyToken=de2b1c089621e923</value>
|
||||
</data>
|
||||
<data name="GrasscutterToolsSupport.MaximumSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>280, 280</value>
|
||||
</data>
|
||||
<data name=">>LnkOpenChat.Name" xml:space="preserve">
|
||||
<value>LnkOpenChat</value>
|
||||
</data>
|
||||
<data name=">>LblSupportDescription.Name" xml:space="preserve">
|
||||
<value>LblSupportDescription</value>
|
||||
<data name="GrasscutterToolsSupport.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>140, 140</value>
|
||||
</data>
|
||||
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
|
||||
<value>7, 17</value>
|
||||
</data>
|
||||
<data name=">>LnkGithub.Name" xml:space="preserve">
|
||||
<value>LnkGithub</value>
|
||||
@@ -217,8 +217,8 @@
|
||||
<data name="LnkOpenChat.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>9</value>
|
||||
</data>
|
||||
<data name="GrasscutterToolsSupport.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>140, 140</value>
|
||||
<data name="LnkGithub.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Bottom, Left</value>
|
||||
</data>
|
||||
<data name="GrasscutterToolsSupport.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>8</value>
|
||||
@@ -226,8 +226,8 @@
|
||||
<data name=">>GrasscutterToolsSupport.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="GrasscutterToolsSupport.MaximumSize" type="System.Drawing.Size, System.Drawing">
|
||||
<value>280, 280</value>
|
||||
<data name="LnkOpenChat.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
|
||||
<value>MiddleCenter</value>
|
||||
</data>
|
||||
<data name="LnkGithub.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
@@ -265,7 +265,4 @@
|
||||
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>True</value>
|
||||
</metadata>
|
||||
<metadata name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>ru-RU</value>
|
||||
</metadata>
|
||||
</root>
|
||||
</root>
|
@@ -31,6 +31,7 @@
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PageAchievement));
|
||||
this.ListAchievements = new System.Windows.Forms.ListBox();
|
||||
this.GrpAchievements = new System.Windows.Forms.GroupBox();
|
||||
this.LblClearFilter = new System.Windows.Forms.Label();
|
||||
this.TxtAchievementFilter = new System.Windows.Forms.TextBox();
|
||||
this.LnkRevokeAll = new System.Windows.Forms.LinkLabel();
|
||||
this.LnkGrantAll = new System.Windows.Forms.LinkLabel();
|
||||
@@ -50,10 +51,12 @@
|
||||
this.ListAchievements.FormattingEnabled = true;
|
||||
this.ListAchievements.Name = "ListAchievements";
|
||||
this.ListAchievements.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
|
||||
this.ListAchievements.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.ListAchievements_MeasureItem);
|
||||
//
|
||||
// GrpAchievements
|
||||
//
|
||||
resources.ApplyResources(this.GrpAchievements, "GrpAchievements");
|
||||
this.GrpAchievements.Controls.Add(this.LblClearFilter);
|
||||
this.GrpAchievements.Controls.Add(this.TxtAchievementFilter);
|
||||
this.GrpAchievements.Controls.Add(this.LnkRevokeAll);
|
||||
this.GrpAchievements.Controls.Add(this.ListAchievements);
|
||||
@@ -61,6 +64,14 @@
|
||||
this.GrpAchievements.Name = "GrpAchievements";
|
||||
this.GrpAchievements.TabStop = false;
|
||||
//
|
||||
// LblClearFilter
|
||||
//
|
||||
resources.ApplyResources(this.LblClearFilter, "LblClearFilter");
|
||||
this.LblClearFilter.BackColor = System.Drawing.Color.White;
|
||||
this.LblClearFilter.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.LblClearFilter.Name = "LblClearFilter";
|
||||
this.LblClearFilter.Click += new System.EventHandler(this.LblClearFilter_Click);
|
||||
//
|
||||
// TxtAchievementFilter
|
||||
//
|
||||
resources.ApplyResources(this.TxtAchievementFilter, "TxtAchievementFilter");
|
||||
@@ -154,5 +165,6 @@
|
||||
private System.Windows.Forms.TextBox TxtAchievementFilter;
|
||||
private System.Windows.Forms.LinkLabel LnkRevokeAll;
|
||||
private System.Windows.Forms.LinkLabel LnkGrantAll;
|
||||
private System.Windows.Forms.Label LblClearFilter;
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,8 @@ namespace GrasscutterTools.Pages
|
||||
{
|
||||
internal partial class PageAchievement : BasePage
|
||||
{
|
||||
public override string Text => Resources.PageAchievementTitle;
|
||||
|
||||
public PageAchievement()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -52,6 +54,15 @@ namespace GrasscutterTools.Pages
|
||||
private void TxtAchievementFilter_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateList();
|
||||
LblClearFilter.Visible = TxtAchievementFilter.Text.Length > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击清空过滤器标签时触发
|
||||
/// </summary>
|
||||
private void LblClearFilter_Click(object sender, EventArgs e)
|
||||
{
|
||||
TxtAchievementFilter.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -98,5 +109,10 @@ namespace GrasscutterTools.Pages
|
||||
{
|
||||
GenSelected("/achievement progress", NUDProgress.Text);
|
||||
}
|
||||
|
||||
private void ListAchievements_MeasureItem(object sender, MeasureItemEventArgs e)
|
||||
{
|
||||
e.ItemHeight = ListAchievements.Font.Height * 3 / 2;
|
||||
}
|
||||
}
|
||||
}
|
@@ -145,11 +145,47 @@
|
||||
<value>GrpAchievements</value>
|
||||
</data>
|
||||
<data name=">>ListAchievements.ZOrder" xml:space="preserve">
|
||||
<value>2</value>
|
||||
<value>3</value>
|
||||
</data>
|
||||
<data name="GrpAchievements.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Bottom, Left, Right</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.AutoSize" type="System.Boolean, mscorlib">
|
||||
<value>True</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
|
||||
<value>NoControl</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>617, 25</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>16, 17</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>18</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Text" xml:space="preserve">
|
||||
<value>X</value>
|
||||
</data>
|
||||
<data name="LblClearFilter.Visible" type="System.Boolean, mscorlib">
|
||||
<value>False</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.Name" xml:space="preserve">
|
||||
<value>LblClearFilter</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.Parent" xml:space="preserve">
|
||||
<value>GrpAchievements</value>
|
||||
</data>
|
||||
<data name=">>LblClearFilter.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="TxtAchievementFilter.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Left, Right</value>
|
||||
</data>
|
||||
@@ -172,7 +208,7 @@
|
||||
<value>GrpAchievements</value>
|
||||
</data>
|
||||
<data name=">>TxtAchievementFilter.ZOrder" xml:space="preserve">
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="LnkRevokeAll.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
@@ -202,7 +238,7 @@
|
||||
<value>GrpAchievements</value>
|
||||
</data>
|
||||
<data name=">>LnkRevokeAll.ZOrder" xml:space="preserve">
|
||||
<value>1</value>
|
||||
<value>2</value>
|
||||
</data>
|
||||
<data name="LnkGrantAll.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
|
||||
<value>Top, Right</value>
|
||||
@@ -232,7 +268,7 @@
|
||||
<value>GrpAchievements</value>
|
||||
</data>
|
||||
<data name=">>LnkGrantAll.ZOrder" xml:space="preserve">
|
||||
<value>3</value>
|
||||
<value>4</value>
|
||||
</data>
|
||||
<data name="GrpAchievements.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>3, 3</value>
|
||||
@@ -394,6 +430,6 @@
|
||||
<value>PageAchievement</value>
|
||||
</data>
|
||||
<data name=">>$this.Type" xml:space="preserve">
|
||||
<value>GrasscutterTools.Pages.BasePage, GrasscutterTools, Version=1.9.0.0, Culture=neutral, PublicKeyToken=de2b1c089621e923</value>
|
||||
<value>GrasscutterTools.Pages.BasePage, GrasscutterTools, Version=1.13.0.0, Culture=neutral, PublicKeyToken=de2b1c089621e923</value>
|
||||
</data>
|
||||
</root>
|
@@ -22,12 +22,15 @@ using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using GrasscutterTools.Game;
|
||||
using GrasscutterTools.Properties;
|
||||
using GrasscutterTools.Utils;
|
||||
|
||||
namespace GrasscutterTools.Pages
|
||||
{
|
||||
internal partial class PageAvatar : BasePage
|
||||
{
|
||||
public override string Text => Resources.PageAvatarTitle;
|
||||
|
||||
public PageAvatar()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
@@ -39,6 +39,7 @@
|
||||
this.BtnSaveCustomCommand = new System.Windows.Forms.Button();
|
||||
this.TxtCustomName = new System.Windows.Forms.TextBox();
|
||||
this.BtnAddHotKey = new System.Windows.Forms.Button();
|
||||
this.LblClearFilter = new System.Windows.Forms.Label();
|
||||
this.GrpCustomCommands.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
@@ -99,6 +100,7 @@
|
||||
//
|
||||
resources.ApplyResources(this.TxtCustomName, "TxtCustomName");
|
||||
this.TxtCustomName.Name = "TxtCustomName";
|
||||
this.TxtCustomName.TextChanged += new System.EventHandler(this.TxtCustomName_TextChanged);
|
||||
this.TxtCustomName.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TxtCustomName_KeyDown);
|
||||
//
|
||||
// BtnAddHotKey
|
||||
@@ -108,10 +110,19 @@
|
||||
this.BtnAddHotKey.UseVisualStyleBackColor = true;
|
||||
this.BtnAddHotKey.Click += new System.EventHandler(this.BtnAddHotKey_Click);
|
||||
//
|
||||
// LblClearFilter
|
||||
//
|
||||
resources.ApplyResources(this.LblClearFilter, "LblClearFilter");
|
||||
this.LblClearFilter.BackColor = System.Drawing.Color.White;
|
||||
this.LblClearFilter.Cursor = System.Windows.Forms.Cursors.Hand;
|
||||
this.LblClearFilter.Name = "LblClearFilter";
|
||||
this.LblClearFilter.Click += new System.EventHandler(this.LblClearFilter_Click);
|
||||
//
|
||||
// PageCustomCommands
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.LblClearFilter);
|
||||
this.Controls.Add(this.BtnAddHotKey);
|
||||
this.Controls.Add(this.BtnExportCustomCommands);
|
||||
this.Controls.Add(this.BtnLoadCustomCommands);
|
||||
@@ -140,5 +151,6 @@
|
||||
private System.Windows.Forms.Button BtnSaveCustomCommand;
|
||||
private System.Windows.Forms.TextBox TxtCustomName;
|
||||
private System.Windows.Forms.Button BtnAddHotKey;
|
||||
private System.Windows.Forms.Label LblClearFilter;
|
||||
}
|
||||
}
|
||||
|