Compare commits

..

73 Commits

Author SHA1 Message Date
e201281c36 Update version to v1.17.1 2025-01-27 11:39:10 +08:00
cbd81f92f4 Update activity 2025-01-27 11:34:47 +08:00
dplek
f364754092 Update missing stuff to v5.3 (#240)
* Update Quest to v5.3

* Update Activity.txt to v5.3
2025-01-27 11:29:47 +08:00
8b760e5e9b Fix page order issue 2025-01-13 18:57:09 +08:00
3b2bfbb0e6 Update version to v1.17.0 2025-01-13 18:50:10 +08:00
2c8691e9ae Update resources to 5.3
Include Achievement, Avatar, Cutscene, Dungeon, BannerTitle, Gadget, Item, Monster, Scene, Weapon...
2025-01-13 18:48:24 +08:00
剧毒的KCN
e6a2d26671 Fix ListBox overflow on high DPI (#235) 2024-09-07 21:35:50 +08:00
fafff8090f Fix height issue of nav list items on high dpi 2024-09-07 20:44:23 +08:00
Amireux
b37016a49c Added 5.0 Banners (#232)
Some checks failed
Build project / build (push) Has been cancelled
Added missing event IDs
Added 5.0 Banners in the Prize Pool Editor
2024-08-29 09:54:14 +08:00
6e8c1d4a15 Update version to v1.16.0
Some checks are pending
Build project / build (push) Waiting to run
2024-08-28 23:05:54 +08:00
92f5289576 Update All resources to 5.0 2024-08-28 23:05:06 +08:00
剧毒的KCN
c62b46850c Enable High DPI support (#231) 2024-06-23 22:34:03 +08:00
3d160f9b90 Update version to v1.15.2 2024-06-16 17:06:25 +08:00
79efb9bd51 Update some resources to 4.7 2024-06-16 17:06:25 +08:00
ef3c85c6d3 Fix Quest text 2024-06-09 12:20:06 +08:00
Jtuiii
e61fc45ad2 Update 4.7.0 Quest (#229) 2024-06-09 11:44:22 +08:00
de53f682f0 Add quick finish quest 2024-05-30 23:51:36 +08:00
3ddfa189e9 Update version to 1.15.1 2024-05-30 23:34:49 +08:00
ddc588c792 Update banners from https://github.com/Zhaokugua/Grasscutter_Banners 2024-05-30 23:33:49 +08:00
984afbdf0b Update banner titles to 4.6
Fix benner editor format
Add banner title update tool
2024-05-30 23:33:37 +08:00
56a72ad940 Rename banner resource files 2024-05-30 23:30:38 +08:00
b62c539bdd Update version to v1.15.0 2024-05-23 20:00:55 +08:00
d9272acb44 Update all resource to 4.6 2024-05-23 19:59:39 +08:00
5c89eb5a58 Update artifact set names 2024-03-31 15:49:42 +08:00
583041c295 Update version to v1.14.0 2024-03-25 00:15:04 +08:00
ded10d175f Update All Resources to 4.5.0 2024-03-25 00:14:30 +08:00
380682d175 Fix resource id 0 2024-03-24 23:33:59 +08:00
055bddc22c Fix proxy close issue 2024-03-24 23:33:59 +08:00
5b2442591f Fix include UID space issue 2023-11-12 13:54:49 +08:00
3eb1a08697 Fix #204 2023-10-30 23:35:10 +08:00
79283f4039 Optimize navigation framework 2023-10-21 09:42:00 +08:00
497b828f2d Fix clear button misalignment 2023-10-20 20:02:40 +08:00
41dc3e8fc4 Update weather translation(CHS) 2023-10-20 19:32:24 +08:00
eb1be4cdb8 Add reset all scene tag 2023-10-18 23:17:59 +08:00
d4655c1e50 Update change log 2023-10-18 23:07:12 +08:00
b1debe0aab Add clear button to command box 2023-10-18 23:03:25 +08:00
f5780a4366 Fix UI issues 2023-10-18 22:49:45 +08:00
101e3c5ffc Add clear button to all filter 2023-10-18 22:38:27 +08:00
97b3a57ee1 Add non aggressive AI option to spawn page 2023-10-18 22:19:08 +08:00
0788a32158 Fix command response new line 2023-10-18 22:05:51 +08:00
f553ddddd8 Add weather page translates 2023-10-18 22:05:29 +08:00
07fb477c3a Fix hotkey registration control 2023-10-14 15:55:57 +08:00
f8b920100d Add Weather Page 2023-10-14 11:36:17 +08:00
cfdca6f031 Fix nav error 2023-10-13 23:09:05 +08:00
085669e43a Add proxy page translation 2023-10-13 23:08:43 +08:00
eda70a2aae Add Settings page
Add Page tab order setting
Add Window opacity setting
2023-10-13 22:45:24 +08:00
c2be92c41b Fix hotkey registration issue 2023-10-08 12:23:13 +08:00
4bcd23389d Move stop proxy code 2023-10-08 00:09:25 +08:00
2a51fcb47d Add Proxy page 2023-10-08 00:01:20 +08:00
2c2f05c5b2 Add SceneTag Page 2023-10-07 22:22:35 +08:00
ab92469f11 Fix include uid bug 2023-10-07 21:24:59 +08:00
749f324f7d Add hotkey global switch 2023-09-29 15:04:30 +08:00
1c49c41b71 Update 4.1 resources(Avatar/Dungeon/Item/Weapon ) 2023-09-29 14:13:58 +08:00
1993d3d295 Fix include uid symbol issue 2023-09-24 00:27:55 +08:00
dce7e54675 Add HTTP(S) proxy (#208) 2023-09-23 10:48:24 +08:00
41c644f2af Add Run multiple commands at one time 2023-09-20 12:56:38 +08:00
78be273c7a Add dive prop 2023-08-29 00:12:01 +08:00
c94a7683e4 Update tab order 2023-08-25 19:53:40 +08:00
b407012bef Add FreezeTime and LockWeather to scene page 2023-08-25 19:47:23 +08:00
bb7d28153f Enlarge custom commands font size 2023-08-25 19:39:30 +08:00
627d9c7cd2 Add fly command 2023-08-25 19:37:14 +08:00
53a83fd7a7 Update version to v1.12.2 2023-08-24 19:51:49 +08:00
c2ca091662 Update Items filter 2023-08-24 19:51:30 +08:00
738a755353 Update All Gadgets
Update Spawn filter
2023-08-24 19:41:30 +08:00
dcbd946407 Fix console include @uid issue 2023-08-24 17:16:30 +08:00
2a8cebcbb5 Clean up all code 2023-08-24 15:18:12 +08:00
434ec7b2df Fix Jadefall's Splendor 2023-08-24 14:57:15 +08:00
c2ff37facf Update scene dungeon names 2023-08-24 13:49:15 +08:00
f48c9b4d0b Update 4.0 Quests 2023-08-24 00:02:19 +08:00
1d734479d1 Update filter button UI 2023-08-23 23:34:13 +08:00
a989581d59 Swap the run and copy button positions 2023-08-23 23:05:24 +08:00
6ab9d3842c Update version to v1.12.1 2023-08-23 22:40:42 +08:00
b69b2941b6 Fix auto check local server error 2023-08-23 22:39:40 +08:00
280 changed files with 149401 additions and 62808 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -34,6 +34,15 @@ The server require [gc-opencommand-plugin](https://github.com/jie65535/gc-openco
## Update log
### GrasscutterTools-v1.13
![Proxy](Doc/Screenshots-en/22-Proxy.png)
![SceneTag](Doc/Screenshots-en/23-SceneTag.png)
![Weather](Doc/Screenshots-en/24-Weather.png)
![Settings](Doc/Screenshots-en/25-Settings.png)
### GrasscutterTools-v1.11
![HotKey](Doc/Screenshots-en/21-HotKey.png)

View File

@@ -35,6 +35,15 @@ GCG поддерживает 简体中文 (китайский упр.), 繁體
## Лог обновлений
### GrasscutterTools-v1.13
![Proxy](Doc/Screenshots-en/22-Proxy.png)
![SceneTag](Doc/Screenshots-en/23-SceneTag.png)
![Weather](Doc/Screenshots-en/24-Weather.png)
![Settings](Doc/Screenshots-en/25-Settings.png)
### GrasscutterTools-v1.11
![HotKey](Doc/Screenshots-en/21-HotKey.png)

View File

@@ -35,6 +35,15 @@
## 更新概要
### GrasscutterTools-v1.13
![Proxy](Doc/Screenshots/22-Proxy.png)
![SceneTag](Doc/Screenshots/23-SceneTag.png)
![Weather](Doc/Screenshots/24-Weather.png)
![Settings](Doc/Screenshots/25-Settings.png)
### GrasscutterTools-v1.11
![HotKey](Doc/Screenshots/21-HotKey.png)

View File

@@ -34,6 +34,15 @@
## 更新日誌
### GrasscutterTools-v1.13
![Proxy](Doc/Screenshots/22-Proxy.png)
![SceneTag](Doc/Screenshots/23-SceneTag.png)
![Weather](Doc/Screenshots/24-Weather.png)
![Settings](Doc/Screenshots/25-Settings.png)
### GrasscutterTools-v1.11
![HotKey](Doc/Screenshots/21-HotKey.png)

View File

@@ -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>

View File

@@ -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)
{

View File

@@ -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; }

View 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();
}
}

View 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();
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
namespace Eavesdrop
{
[Flags]
public enum Interceptors
{
None = 0,
HTTP = 1,
HTTPS = 2,
Default = (HTTP | HTTPS)
}
}

View 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
}
}
}

View 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);
}
}

View 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.

View 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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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 - -
}
}

View File

@@ -241,7 +241,7 @@
<value>GrpMonsterList</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;LblClearMonsterFilter.Name" xml:space="preserve">
<value>LblClearMonsterFilter</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblClearMonsterFilter.Parent" xml:space="preserve">
<value>GrpMonsterList</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblClearItemFilter.Name" xml:space="preserve">
<value>LblClearItemFilter</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblClearItemFilter.Parent" xml:space="preserve">
<value>GrpItemList</value>
</data>
<data name="&gt;&gt;LblClearItemFilter.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="GrpItemList.Location" type="System.Drawing.Point, System.Drawing">
<value>576, 41</value>
</data>

View File

@@ -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,

View File

@@ -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(),

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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 = "";
}
}
}

View File

@@ -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>

View File

@@ -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="&gt;&gt;TCMain.Name" xml:space="preserve">
<value>TCMain</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;TCMain.Parent" xml:space="preserve">
<value>NavContainer.Panel2</value>
</data>
<data name="&gt;&gt;TCMain.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;LblClearFilter.Name" xml:space="preserve">
<value>LblClearFilter</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblClearFilter.Parent" xml:space="preserve">
<value>GrpCommand</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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>

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}

View File

@@ -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="&gt;&gt;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="&gt;&gt;$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="&gt;&gt;BtnSearch.Name" xml:space="preserve">
<value>BtnSearch</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;BtnSearch.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;TxtTextMapFilter.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;DGVTextMap.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;ColumnHash.Name" xml:space="preserve">
<value>ColumnHash</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;CmbLanguage.ZOrder" xml:space="preserve">
<value>4</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;BtnSearch.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;ColumnText.Name" xml:space="preserve">
<value>ColumnText</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>FormTextMapBrowser</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;BtnSelectRecoursePath.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;ChkTopMost.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;TxtTextMapFilter.ZOrder" xml:space="preserve">
<value>7</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;LblLanguage.Parent" xml:space="preserve">
<data name="&gt;&gt;TxtTextMapFilter.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="LblLanguage.Text" xml:space="preserve">
<value>语言</value>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;BtnSelectRecoursePath.Name" xml:space="preserve">
<value>BtnSelectRecoursePath</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;BtnSelectRecoursePath.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;CmbLanguage.Name" xml:space="preserve">
<value>CmbLanguage</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;CmbLanguage.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblLanguage.Name" xml:space="preserve">
<value>LblLanguage</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblLanguage.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;ChkTopMost.Name" xml:space="preserve">
<value>ChkTopMost</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;ChkTopMost.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblResourcesPath.Name" xml:space="preserve">
<value>LblResourcesPath</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblResourcesPath.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;BtnSearch.Name" xml:space="preserve">
<value>BtnSearch</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;BtnSearch.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;DGVTextMap.Name" xml:space="preserve">
<value>DGVTextMap</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;DGVTextMap.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblClearFilter.Name" xml:space="preserve">
<value>LblClearFilter</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblClearFilter.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;ColumnHash.Name" xml:space="preserve">
<value>ColumnHash</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;ColumnText.Name" xml:space="preserve">
<value>ColumnText</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;ColumnID.Name" xml:space="preserve">
<value>ColumnID</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;$this.Name" xml:space="preserve">
<value>FormTextMapBrowser</value>
</data>
<data name="&gt;&gt;$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>

View File

@@ -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"

View File

@@ -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"

View File

@@ -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; }

View File

@@ -26,7 +26,7 @@ using GrasscutterTools.Properties;
namespace GrasscutterTools.GOOD
{
public static class GOODData
internal static class GOODData
{
static GOODData()
{

View File

@@ -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"

View File

@@ -24,7 +24,7 @@ using Newtonsoft.Json;
namespace GrasscutterTools.Game.Activity
{
public class ActivityConfigItem
internal class ActivityConfigItem
{
/// <summary>
/// 活动ID

View File

@@ -163,10 +163,20 @@ namespace GrasscutterTools.Game
public static readonly Version V1_6_3 = new Version(1, 6, 3);
/// <summary>
/// 2023/??
/// 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
@@ -190,6 +200,8 @@ namespace GrasscutterTools.Game
V1_6_2,
V1_6_3,
V1_7_0,
V1_7_1,
V1_7_2,
};
#endregion - Version List -

View File

@@ -17,10 +17,12 @@
*
**/
using GrasscutterTools.Game.Data;
using Newtonsoft.Json;
namespace GrasscutterTools.Game.CutScene
{
[ResourceType("CutsceneExcelConfigData.json")]
internal class CutSceneItem
{
[JsonProperty("id")]

View File

@@ -1,4 +1,23 @@
using Newtonsoft.Json;
/**
* 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
{
@@ -10,4 +29,4 @@ namespace GrasscutterTools.Game.Data.Excels
public bool IsUsed => !IsDisuse;
}
}
}

View File

@@ -1,4 +1,23 @@
using GrasscutterTools.Game.Props;
/**
* 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;
@@ -11,4 +30,4 @@ namespace GrasscutterTools.Game.Data.Excels
[JsonProperty("qualityType"), JsonConverter(typeof(StringEnumConverter))]
public QualityType QualityType { get; set; }
}
}
}

View File

@@ -1,7 +1,30 @@
namespace GrasscutterTools.Game.Data.Excels
/**
* 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; }
}
}
}

View File

@@ -1,13 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/**
* 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
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; }
}
}
}

View 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; }
}
}

View File

@@ -1,4 +1,23 @@
using Newtonsoft.Json;
/**
* 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
{
@@ -11,4 +30,4 @@ namespace GrasscutterTools.Game.Data.Excels
[JsonProperty("bgmNameTextMapHash")]
public long BgmNameTextMapHash { get; set; }
}
}
}

View File

@@ -1,7 +1,30 @@
namespace GrasscutterTools.Game.Data.Excels
/**
* 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; }
}
}
}

View File

@@ -1,4 +1,21 @@
using Newtonsoft.Json;
/**
* 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
{
@@ -6,4 +23,4 @@ namespace GrasscutterTools.Game.Data.Excels
internal class MainQuestData : GameResource
{
}
}
}

View File

@@ -1,4 +1,24 @@
using System.Collections.Generic;
/**
* 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;
@@ -19,4 +39,4 @@ namespace GrasscutterTools.Game.Data.Excels
[JsonProperty("itemUse")]
public List<ItemUseData> ItemUse { get; set; }
}
}
}

View File

@@ -1,4 +1,24 @@
using GrasscutterTools.Game.Props;
/**
* 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
@@ -12,4 +32,4 @@ namespace GrasscutterTools.Game.Data.Excels
[JsonProperty("type")]
public MonsterType Type { get; set; }
}
}
}

View File

@@ -1,4 +1,23 @@
using Newtonsoft.Json;
/**
* 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
{
@@ -14,4 +33,4 @@ namespace GrasscutterTools.Game.Data.Excels
[JsonProperty("order")]
public int Order { get; set; }
}
}
}

View File

@@ -1,7 +1,26 @@
namespace GrasscutterTools.Game.Data.Excels
/**
* 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
{
}
}
}

View File

@@ -1,4 +1,24 @@
using GrasscutterTools.Game.Props;
/**
* 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
@@ -12,4 +32,4 @@ namespace GrasscutterTools.Game.Data.Excels
[JsonProperty("scriptData")]
public string ScriptData { get; set; }
}
}
}

View 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; }
}
}

View File

@@ -1,4 +1,23 @@
using Newtonsoft.Json;
/**
* 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
{
@@ -8,4 +27,4 @@ namespace GrasscutterTools.Game.Data.Excels
[JsonProperty("rankLevel")]
public int RankLevel { get; set; }
}
}
}

View 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; }
}
}

View File

@@ -1,4 +1,23 @@
using Newtonsoft.Json;
/**
* 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
{
@@ -11,7 +30,7 @@ namespace GrasscutterTools.Game.Data
public long NameTextMapHash { get; set; }
[JsonProperty("titleTextMapHash")]
public string TitleTextMapHash { get; set; }
public long TitleTextMapHash { get; set; }
[JsonProperty("descTextMapHash")]
public long DescTextMapHash { get; set; }

View File

@@ -1,4 +1,23 @@
using System;
/**
* 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;
@@ -6,10 +25,10 @@ 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.GOOD;
using GrasscutterTools.Utils;
using Newtonsoft.Json;
@@ -26,8 +45,12 @@ namespace GrasscutterTools.Game.Data
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; }
@@ -37,14 +60,17 @@ namespace GrasscutterTools.Game.Data
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)
{
@@ -55,18 +81,24 @@ namespace GrasscutterTools.Game.Data
{
var type = property.PropertyType;
if (!type.IsGenericType) continue;
var gameResourceType = type.GetGenericArguments()[1];
var attributes = (ResourceTypeAttribute[])gameResourceType.GetCustomAttributes(typeof(ResourceTypeAttribute), true);
if (attributes.Length < 1) continue;
var dataFile = Path.Combine(resourcesDirPath, "ExcelBinOutput", attributes[0].Name);
var data = LoadDataFile(gameResourceType, dataFile);
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, 14505, 14508, 15504-15506, 20001");
"13503, 13506, 14411, 14503, 14508, 15504-15506, 20001");
foreach (var id in WeaponData.Keys.Where(id => illegalWeaponIds.Contains(id)).ToList())
WeaponData.Remove(id);
@@ -96,22 +128,43 @@ namespace GrasscutterTools.Game.Data
private static object LoadDataFile(Type type, string path)
{
var list = (IList)JsonConvert.DeserializeObject(File.ReadAllText(path), typeof(List<>).MakeGenericType(type));
if (list == null) return null;
var dicType = typeof(Dictionary<,>).MakeGenericType(typeof(int), type);
var dic = (IDictionary)Activator.CreateInstance(dicType);
foreach (GameResource gameResource in list)
dic.Add(gameResource.Id, gameResource);
return dic;
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",
["en-us"] = "TextMapEN",
["ru-ru"] = "TextMapRU",
};
public void ConvertResources(string projectResourcesDir)
@@ -128,17 +181,30 @@ namespace GrasscutterTools.Game.Data
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
@@ -146,11 +212,104 @@ namespace GrasscutterTools.Game.Data
.Select(it => $"{it.Id}:{TextMapData.GetText(it.NameTextMapHash.ToString())}"),
Encoding.UTF8);
File.WriteAllLines(
#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"),
DungeonData.Values.Select(it => $"{it.Id}:{TextMapData.GetText(it.NameTextMapHash.ToString())}"),
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))
{
@@ -167,11 +326,16 @@ namespace GrasscutterTools.Game.Data
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()),
TextMapData.GetText(HomeWorldBgmData[int.Parse(materialData.ItemUse[0].UseParam[0])].BgmNameTextMapHash.ToString())
).AppendLine();
name);
sb.AppendLine();
}
}
else
{
@@ -195,7 +359,11 @@ namespace GrasscutterTools.Game.Data
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)
@@ -225,29 +393,136 @@ namespace GrasscutterTools.Game.Data
sb.ToString(),
Encoding.UTF8);
File.WriteAllLines(
#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"),
QuestData.Values.OrderBy(it => it.Id).Select(it => $"{it.Id}:{TextMapData.GetText(MainQuestData[it.MainId].TitleTextMapHash)} - {TextMapData.GetText(it.DescTextMapHash.ToString())}"),
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))
{
var name = GameData.Scenes[it.Id];
sb.AppendLine($"{it.Id}:{(name == ItemMap.EmptyName ? it.ScriptData : name)}");
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"),
@@ -258,7 +533,6 @@ namespace GrasscutterTools.Game.Data
Path.Combine(projectResourcesDir, "WeaponColor.txt"),
WeaponData.Values.Select(it => $"{it.Id}:{(it.RankLevel >= 5 ? "yellow" : it.RankLevel >= 4 ? "purple" : "blue")}"),
Encoding.UTF8);
}
finally
{
@@ -266,4 +540,4 @@ namespace GrasscutterTools.Game.Data
}
}
}
}
}

View File

@@ -1,9 +1,28 @@
using System;
/**
* 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)]
public class ResourceTypeAttribute : Attribute
internal class ResourceTypeAttribute : Attribute
{
public string Name { get; set; }
@@ -12,4 +31,4 @@ namespace GrasscutterTools.Game.Data
Name = name;
}
}
}
}

View File

@@ -28,7 +28,7 @@ namespace GrasscutterTools.Game.Gacha
/// 使用这个只需替换掉你原来的的data/banner.json文件
/// 然后重启服务器和客户端,即可享受全卡池抽卡,卡池的选择方式是点击左右箭头进行切换
/// </summary>
public class GachaBanner
internal class GachaBanner
{
/// <summary>
/// 添加卡池请从400开始增加id数值进行添加这个id需要每个池子不一样

View File

@@ -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需要每个池子不一样

View File

@@ -28,7 +28,7 @@ namespace GrasscutterTools.Game.Gacha
/// <summary>
/// https://github.com/Grasscutters/Grasscutter/pull/639
/// </summary>
public class GachaBanner3
internal class GachaBanner3
{
/// <summary>
/// 备注

View File

@@ -22,7 +22,7 @@ using System.Text;
namespace GrasscutterTools.Game
{
public class GameCommand
internal class GameCommand
{
public GameCommand(string name, string command)
{

View File

@@ -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; }
}
}

View File

@@ -2,7 +2,6 @@
// ReSharper disable InconsistentNaming
// ReSharper disable IdentifierTypo
using System;
using System.Collections.Generic;
namespace GrasscutterTools.Game.Inventory
@@ -12,54 +11,70 @@ namespace GrasscutterTools.Game.Inventory
/// </summary>
internal enum MaterialType
{
MATERIAL_NONE = 0,
MATERIAL_FOOD = 1,
MATERIAL_QUEST = 2,
MATERIAL_EXCHANGE = 4,
MATERIAL_CONSUME = 5,
MATERIAL_EXP_FRUIT = 6,
MATERIAL_AVATAR = 7,
MATERIAL_ADSORBATE = 8,
MATERIAL_CRICKET = 9,
MATERIAL_ELEM_CRYSTAL = 10,
MATERIAL_WEAPON_EXP_STONE = 11,
MATERIAL_CHEST = 12,
MATERIAL_RELIQUARY_MATERIAL = 13,
MATERIAL_AVATAR_MATERIAL = 14,
MATERIAL_NOTICE_ADD_HP = 15,
MATERIAL_SEA_LAMP = 16,
MATERIAL_SELECTABLE_CHEST = 17,
MATERIAL_FLYCLOAK = 18,
MATERIAL_NAMECARD = 19,
MATERIAL_TALENT = 20,
MATERIAL_WIDGET = 21,
MATERIAL_CHEST_BATCH_USE = 22,
MATERIAL_FAKE_ABSORBATE = 23,
MATERIAL_CONSUME_BATCH_USE = 24,
MATERIAL_WOOD = 25,
MATERIAL_FURNITURE_FORMULA = 27,
MATERIAL_CHANNELLER_SLAB_BUFF = 28,
MATERIAL_FURNITURE_SUITE_FORMULA = 29,
MATERIAL_COSTUME = 30,
MATERIAL_HOME_SEED = 31,
MATERIAL_FISH_BAIT = 32,
MATERIAL_FISH_ROD = 33,
MATERIAL_SUMO_BUFF = 34, // sumo 活动道具never appear
MATERIAL_FIREWORKS = 35,
MATERIAL_BGM = 36,
MATERIAL_SPICE_FOOD = 37,
MATERIAL_ACTIVITY_ROBOT = 38,
MATERIAL_ACTIVITY_GEAR = 39,
MATERIAL_ACTIVITY_JIGSAW = 40,
MATERIAL_ARANARA = 41,
MATERIAL_GCG_CARD = 42,
MATERIAL_GCG_CARD_FACE = 43, // 影幻卡面
MATERIAL_GCG_CARD_BACK = 44,
MATERIAL_GCG_FIELD = 45,
MATERIAL_DESHRET_MANUAL = 46,
MATERIAL_RENAME_ITEM = 47,
MATERIAL_GCG_EXCHANGE_ITEM = 48,
MATERIAL_QUEST_EVENT_BOOK = 49,
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
@@ -114,6 +129,22 @@ namespace GrasscutterTools.Game.Inventory
[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>
{
@@ -165,10 +196,28 @@ namespace GrasscutterTools.Game.Inventory
[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];
}
}

View File

@@ -22,7 +22,7 @@ using System.Collections.Generic;
namespace GrasscutterTools.Game
{
public class ItemMap
internal class ItemMap
{
public ItemMap(string idNamePairs)
{

View File

@@ -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]
{

View File

@@ -27,7 +27,7 @@ namespace GrasscutterTools.Game.Mail
/// <summary>
/// 邮件
/// </summary>
public class Mail
internal class Mail
{
/// <summary>
/// 发件人

View 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;
}
}
}

View File

@@ -1,4 +1,23 @@
using Newtonsoft.Json;
/**
* 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
{
@@ -7,4 +26,4 @@ namespace GrasscutterTools.Game.Props
[JsonProperty("useParam")]
public string[] UseParam { get; set; }
}
}
}

View File

@@ -1,4 +1,22 @@

/**
* 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;
@@ -19,7 +37,6 @@ namespace GrasscutterTools.Game.Props
MONSTER_PARTNER = 6,
}
internal static class ItemTypeExtension
{
private static readonly Dictionary<MonsterType, string> TextMapCHS = new Dictionary<MonsterType, string>
@@ -32,6 +49,7 @@ namespace GrasscutterTools.Game.Props
[MonsterType.MONSTER_FISH] = "鱼",
[MonsterType.MONSTER_PARTNER] = "友军",
};
private static readonly Dictionary<MonsterType, string> TextMapEN = new Dictionary<MonsterType, string>
{
[MonsterType.MONSTER_NONE] = "None",
@@ -48,4 +66,4 @@ namespace GrasscutterTools.Game.Props
return language.StartsWith("zh") ? TextMapCHS[materialType] : TextMapEN[materialType];
}
}
}
}

View File

@@ -1,4 +1,22 @@

/**
* 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
@@ -41,4 +59,4 @@ namespace GrasscutterTools.Game.Props
//QUALITY_ORANGE_SP = 105,
QUALITY_ORANGE_SP = 5,
}
}
}

View File

@@ -1,4 +1,22 @@

/**
* 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
@@ -13,4 +31,4 @@ namespace GrasscutterTools.Game.Props
SCENE_HOME_ROOM = 5,
SCENE_ACTIVITY = 6,
}
}
}

View File

@@ -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; }

View File

@@ -26,7 +26,7 @@ using Newtonsoft.Json.Converters;
namespace GrasscutterTools.Game.Shop
{
public class ShopInfo
internal class ShopInfo
{
public ShopInfo()
{

View File

@@ -23,7 +23,7 @@ using Newtonsoft.Json;
namespace GrasscutterTools.Game.Shop
{
public class ShopTable
internal class ShopTable
{
[JsonProperty("shopId")]
public int ShopType { get; set; }

View File

@@ -26,7 +26,7 @@ using Newtonsoft.Json;
namespace GrasscutterTools.Game
{
public class TextMapData
internal class TextMapData
{
public TextMapData(string resourcesDirPath)
{

View File

@@ -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>
@@ -143,6 +155,7 @@
<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" />
@@ -151,6 +164,8 @@
<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" />
@@ -171,6 +186,7 @@
<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" />
@@ -265,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>
@@ -277,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>
@@ -301,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">
@@ -312,11 +352,13 @@
<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" />
@@ -487,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>
@@ -567,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>
@@ -591,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>
@@ -603,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>
@@ -630,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>
@@ -665,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>
@@ -694,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" />
@@ -705,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" />
@@ -716,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" />
@@ -730,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" />
@@ -743,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" />
@@ -762,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" />

View 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/>.
*
**/

View File

@@ -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)

View File

@@ -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();

View File

@@ -126,10 +126,10 @@
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;$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="&gt;&gt;LnkOpenChat.Name" xml:space="preserve">
<value>LnkOpenChat</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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>

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -145,11 +145,47 @@
<value>GrpAchievements</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblClearFilter.Name" xml:space="preserve">
<value>LblClearFilter</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;LblClearFilter.Parent" xml:space="preserve">
<value>GrpAchievements</value>
</data>
<data name="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;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="&gt;&gt;$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>

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -21,7 +21,7 @@ using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
using GrasscutterTools.Forms;
using GrasscutterTools.Properties;
using GrasscutterTools.Utils;
@@ -30,6 +30,8 @@ namespace GrasscutterTools.Pages
{
internal partial class PageCustomCommands : BasePage
{
public override string Text => Resources.PageCustomCommandsTitle;
public PageCustomCommands()
{
InitializeComponent();
@@ -249,8 +251,9 @@ namespace GrasscutterTools.Pages
}
}
public Action<string> OnAddHotKey;
/// <summary>
/// 点击添加快捷键时触发
/// </summary>
private void BtnAddHotKey_Click(object sender, EventArgs e)
{
var name = TxtCustomName.Text.Trim();
@@ -259,7 +262,27 @@ namespace GrasscutterTools.Pages
MessageBox.Show(Resources.CommandTagCannotBeEmpty, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
OnAddHotKey?.Invoke(name);
// 跳转到快捷键界面
FormMain.Instance.NavigateTo<PageHotKey>()?
.AddNewHotKey(name); // 设置标签
}
/// <summary>
/// 标签栏文本改变时触发
/// </summary>
private void TxtCustomName_TextChanged(object sender, EventArgs e)
{
LblClearFilter.Visible = TxtCustomName.Text.Length > 0;
}
/// <summary>
/// 点击清空标签栏标签时触发
/// </summary>
private void LblClearFilter_Click(object sender, EventArgs e)
{
TxtCustomName.Clear();
}
}
}

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