Compare commits
No commits in common. "main" and "v1.7.0" have entirely different histories.
32
.github/workflows/build.yml
vendored
@ -1,32 +0,0 @@
|
|||||||
name: Build project
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- Source/**
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- Source/**
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup MSBuild.exe
|
|
||||||
uses: microsoft/setup-msbuild@v1.1.3
|
|
||||||
|
|
||||||
- name: Build release
|
|
||||||
run: msbuild Source/GrasscutterTools.sln /p:Configuration=Release /t:build /restore
|
|
||||||
|
|
||||||
- name: Upload build artifacts
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: GrasscutterTools
|
|
||||||
path: Source/GrasscutterTools/bin/Release/GrasscutterTools.exe
|
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 36 KiB |
BIN
Doc/Screenshots-ru/0-Home.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
Doc/Screenshots-ru/1-CustomCommands.png
Normal file
After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 18 KiB |
BIN
Doc/Screenshots-ru/10-Waypoints.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
Doc/Screenshots-ru/11-Manage.png
Normal file
After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 18 KiB |
BIN
Doc/Screenshots-ru/12-Credits.png
Normal file
After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 54 KiB |
BIN
Doc/Screenshots-ru/13-Remote.png
Normal file
After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 52 KiB |
BIN
Doc/Screenshots-ru/14-GachaBannerEditor.png
Normal file
After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 95 KiB |
BIN
Doc/Screenshots-ru/15-DropEditor.png
Normal file
After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 48 KiB |
BIN
Doc/Screenshots-ru/15-TextMapBrowser.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
Doc/Screenshots-ru/16-MailEditor.png
Normal file
After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 40 KiB |
BIN
Doc/Screenshots-ru/2-CustomArtifact.png
Normal file
After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 20 KiB |
BIN
Doc/Screenshots-ru/3-Quest.png
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 14 KiB |
BIN
Doc/Screenshots-ru/4-SpawnEntity.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
Doc/Screenshots-ru/5-GiveAvatar.png
Normal file
After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 16 KiB |
BIN
Doc/Screenshots-ru/7-CustomWeapon.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
Doc/Screenshots-ru/8-GiveItem.png
Normal file
After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 15 KiB |
BIN
Doc/Screenshots-ru/9-ChangeScene.png
Normal file
After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 3.6 MiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 821 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 3.6 MiB |
76
README.md
@ -3,19 +3,26 @@
|
|||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/blob/main/LICENSE)
|
[](https://github.com/jie65535/GrasscutterCommandGenerator/blob/main/LICENSE)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/stargazers)
|
[](https://github.com/jie65535/GrasscutterCommandGenerator/stargazers)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases)
|
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases/latest)
|
[](https://qm.qq.com/cgi-bin/qm/qr?k=PdS9--b-n8LEAmYjX8fNFXtKDcsp4NHN&jump_from=webapi&authKey=7ty3ZCKYMKLGWLmO8O84qiNAZ0EuCnSGF+acP+74xuDMKYXXNjuPP7iUzffHz4r2)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/actions/workflows/build.yml)
|
|
||||||
[](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=fBizzp6RwJsIY7gFlmd4L-WG0V3aF8X3&authKey=mTjf%2B7jCIZess1HTRi05e5yi%2FHKA1auMwE8%2FJ960PFWk8WMATST654gWPi4OTHTZ&noverify=0&group_code=835489603)
|
|
||||||
|
|
||||||
English | [简体中文](README_zh-cn.md) | [繁體中文](README_zh-tw.md) | [Русский](README_ru-RU.md)
|
English | [简体中文](README_zh-cn.md) | [Русский](README_ru-RU.md)
|
||||||
|
|
||||||
## Commands Generator
|
## Commands Generator
|
||||||
|
|
||||||
Please download the latest committed automated build from [Action](https://github.com/jie65535/GrasscutterCommandGenerator/actions/workflows/build.yml), or a release from [Releases](https://github.com/jie65535/GrasscutterCommandGenerator/releases) (may be behind)
|
Please download the latest version from [Releases](https://github.com/jie65535/GrasscutterCommandGenerator/releases)
|
||||||
|
|
||||||
Support 简体中文, 繁體中文, English and Русский languages.
|
Support 简体中文, 繁体中文, English and Русский languages.
|
||||||
|
|
||||||
> **Warning**: app look may be different rather than on screenshots. It may also contain translation errors and a lack of certain resources. **We're welcome everyone to contribute to their [improvement](/Source/GrasscutterTools/Resources/en-us)**
|
Welcome everyone to improve the [ID Resource](/Source/GrasscutterTools/Resources/en-us).
|
||||||
|
|
||||||
|
## Update log
|
||||||
|
### GrasscutterTools-v1.7.0
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Remote command
|
## Remote command
|
||||||
|
|
||||||
@ -32,61 +39,6 @@ The server require [gc-opencommand-plugin](https://github.com/jie65535/gc-openco
|
|||||||
>
|
>
|
||||||
> If you are not using port `80`, specify the port number to access in the url: http://127.0.0.1:443
|
> If you are not using port `80`, specify the port number to access in the url: http://127.0.0.1:443
|
||||||
|
|
||||||
## Update log
|
|
||||||
|
|
||||||
### GrasscutterTools-v1.13
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

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

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

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.9
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.8
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.3
|
|
||||||

|
|
||||||
|
|
||||||
Added [AttackModifier](https://github.com/NotThorny/AttackModifier), [AttackInfusedWithItem](https://github.com/snoobi-seggs/AttackInfusedWithItem), [SwitchElementTraveller](https://github.com/Penelopeep/SwitchElementTraveller) plugins command generation
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.2
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.1
|
|
||||||
- Gadgets(CHS Only)
|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.0
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
107
README_ru-RU.md
@ -3,18 +3,25 @@
|
|||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/blob/main/LICENSE)
|
[](https://github.com/jie65535/GrasscutterCommandGenerator/blob/main/LICENSE)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/stargazers)
|
[](https://github.com/jie65535/GrasscutterCommandGenerator/stargazers)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases)
|
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases/latest)
|
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/actions/workflows/build.yml)
|
|
||||||
|
|
||||||
[English](README.md) | [简体中文](README_zh-cn.md) | [繁體中文](README_zh-tw.md) | Русский - Перевод [Юрий Дворецкий](https://github.com/yurikenjx) (с исправлениями от [EgorBron](https://github.com/EgorBron))
|
[English](README.md) | [简体中文](README_zh-cn.md) | Русский - Перевод [Юрий Дворецкий](https://github.com/yurikenjx) (с исправлениями от [EgorBron](https://github.com/EgorBron))
|
||||||
|
|
||||||
## Генератор команд (GCG)
|
## Генератор команд (GCG)
|
||||||
|
|
||||||
Пожалуйста, загрузите последнюю подтвержденную автоматизированную сборку из [Action](https://github.com/jie65535/GrasscutterCommandGenerator/actions/workflows/build.yml) или выпуск из [Releases](https://github.com/jie65535/GrasscutterCommandGenerator/releases) (может отставать)
|
Загрузите последнюю версию из вкладки [Releases](https://github.com/jie65535/GrasscutterCommandGenerator/releases).
|
||||||
|
|
||||||
GCG поддерживает 简体中文 (китайский упр.), 繁體中文 (китайский трад.), English (английский) и Русский языки.
|
GCG поддерживает 简体中文 (китайский упр.), 繁体中文 (китайский трад.), English (английский) и Русский языки.
|
||||||
|
|
||||||
> **Warning**: вид приложения может отличаться от скриншотов. Также в нём могут присутствовать ошибки в переводе и отсутсвие некоторых ресурсов. **Мы приглашаем всех сделать вклад в их [улучшение](/Source/GrasscutterTools/Resources/ru-ru)**
|
Приглашаем всех улучшить [ID ресурсов и перевод](/Source/GrasscutterTools/Resources/ru-ru)
|
||||||
|
|
||||||
|
## Update log
|
||||||
|
### GrasscutterTools-v1.7.0
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Удаленная команда (OpenCommand)
|
## Удаленная команда (OpenCommand)
|
||||||
|
|
||||||
@ -32,96 +39,38 @@ GCG поддерживает 简体中文 (китайский упр.), 繁體
|
|||||||
>
|
>
|
||||||
> Если вы не указали порт `80` в конфиге, вам нужно указать свой порт в URL-адресе (например, http://127.0.0.1:443)
|
> Если вы не указали порт `80` в конфиге, вам нужно указать свой порт в URL-адресе (например, http://127.0.0.1:443)
|
||||||
|
|
||||||
|
|
||||||
## Лог обновлений
|
|
||||||
|
|
||||||
### GrasscutterTools-v1.13
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

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

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

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.9
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.8
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.3
|
|
||||||

|
|
||||||
|
|
||||||
Добавлена поддержка генерации команд для плагинов [AttackModifier](https://github.com/NotThorny/AttackModifier), [AttackInfusedWithItem](https://github.com/snoobi-seggs/AttackInfusedWithItem), [SwitchElementTraveller](https://github.com/Penelopeep/SwitchElementTraveller).
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.2
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.1
|
|
||||||
- Гаджеты (пока что только на китайском)
|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.0
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Скриншоты
|
## Скриншоты
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|
|
@ -3,19 +3,26 @@
|
|||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/blob/main/LICENSE)
|
[](https://github.com/jie65535/GrasscutterCommandGenerator/blob/main/LICENSE)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/stargazers)
|
[](https://github.com/jie65535/GrasscutterCommandGenerator/stargazers)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases)
|
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases/latest)
|
[](https://qm.qq.com/cgi-bin/qm/qr?k=PdS9--b-n8LEAmYjX8fNFXtKDcsp4NHN&jump_from=webapi&authKey=7ty3ZCKYMKLGWLmO8O84qiNAZ0EuCnSGF+acP+74xuDMKYXXNjuPP7iUzffHz4r2)
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/actions/workflows/build.yml)
|
|
||||||
[](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=fBizzp6RwJsIY7gFlmd4L-WG0V3aF8X3&authKey=mTjf%2B7jCIZess1HTRi05e5yi%2FHKA1auMwE8%2FJ960PFWk8WMATST654gWPi4OTHTZ&noverify=0&group_code=835489603)
|
|
||||||
|
|
||||||
[English](README.md) | 简体中文 | [繁體中文](README_zh-tw.md) | [Русский](README_ru-RU.md)
|
[English](README.md) | 简体中文 | [Русский](README_ru-RU.md)
|
||||||
|
|
||||||
## Commands Generator
|
## Commands Generator
|
||||||
|
|
||||||
请从 [Action](https://github.com/jie65535/GrasscutterCommandGenerator/actions/workflows/build.yml) 中下载最新提交的自动构建版本,或者从 [Releases](https://github.com/jie65535/GrasscutterCommandGenerator/releases) 中下载发布版本(可能落后)
|
请从 [Releases](https://github.com/jie65535/GrasscutterCommandGenerator/releases) 中获取最新版本
|
||||||
|
|
||||||
本工具支持 简体中文, 繁體中文, English 与 Русский 语言。
|
本工具支持 简体中文, 繁体中文, English 与 Русский 语言。
|
||||||
|
|
||||||
> **Warning**: 应用程序的外观可能与截图上的不同。它也可能包含翻译错误和缺乏某些资源。**我们欢迎各位为此工具做出贡献并<a href="./Source/GrasscutterTools/Resources/zh-cn">改进</a> : )**
|
欢迎大家一起来完善工具的[内置资源](/Source/GrasscutterTools/Resources/zh-cn)。
|
||||||
|
|
||||||
|
## Update log
|
||||||
|
### GrasscutterTools-v1.7.0
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## 远程执行
|
## 远程执行
|
||||||
|
|
||||||
@ -32,66 +39,6 @@
|
|||||||
>
|
>
|
||||||
> 如果使用的不是`80`端口,则要在url中指定访问的端口号:http://127.0.0.1:443
|
> 如果使用的不是`80`端口,则要在url中指定访问的端口号:http://127.0.0.1:443
|
||||||
|
|
||||||
|
|
||||||
## 更新概要
|
|
||||||
|
|
||||||
### GrasscutterTools-v1.13
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

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

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

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.9
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.8
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.3
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
新增[攻击修改](https://github.com/NotThorny/AttackModifier)、[攻击注入](https://github.com/snoobi-seggs/AttackInfusedWithItem)、[切换元素](https://github.com/Penelopeep/SwitchElementTraveller)等插件命令生成
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.2
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.1
|
|
||||||
- 增加了 Gadgets
|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.0
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 软件截图
|
## 软件截图
|
||||||
|
125
README_zh-tw.md
@ -1,125 +0,0 @@
|
|||||||
# Grasscutter Tools
|
|
||||||
|
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/blob/main/LICENSE)
|
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/stargazers)
|
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases)
|
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/releases/latest)
|
|
||||||
[](https://github.com/jie65535/GrasscutterCommandGenerator/actions/workflows/build.yml)
|
|
||||||
[](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=fBizzp6RwJsIY7gFlmd4L-WG0V3aF8X3&authKey=mTjf%2B7jCIZess1HTRi05e5yi%2FHKA1auMwE8%2FJ960PFWk8WMATST654gWPi4OTHTZ&noverify=0&group_code=835489603)
|
|
||||||
|
|
||||||
[English](README.md) | [简体中文](README_zh-cn.md) | 繁體中文 | [Русский](README_ru-RU.md)
|
|
||||||
|
|
||||||
## 指令產生工具
|
|
||||||
|
|
||||||
請從 [Action](https://github.com/jie65535/GrasscutterCommandGenerator/actions/workflows/build.yml) 中下載最新提交的自動構建版本,或者從 [Releases](https://github.com/jie65535/GrasscutterCommandGenerator/releases) 中下載發布版本(可能落後)
|
|
||||||
|
|
||||||
本工具支援 简体中文、繁體中文、English 及 Русский 上述語言。
|
|
||||||
|
|
||||||
> **Warning**: 程式中的實際外觀可能會與截圖中的內容不同。其中也可能包含翻譯錯誤及缺乏特定資源。**我們歡迎各位為此工具做出貢獻並[改進](/Source/GrasscutterTools/Resources/zh-tw)**
|
|
||||||
|
|
||||||
## 遠端控制
|
|
||||||
|
|
||||||
伺服器需要安裝 [gc-opencommand-plugin](https://github.com/jie65535/gc-opencommand-plugin) 插件
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
> 如果你無法連接至伺服器,請確認輸入的伺服器位址是否正確。
|
|
||||||
>
|
|
||||||
> 建議將伺服器調整為HTTP模式,如下圖所示(config.json):
|
|
||||||
> 
|
|
||||||
>
|
|
||||||
> 你可藉由任何瀏覽器輸入網址 http://127.0.0.1/status/server 以測試伺服器是否正常運作。
|
|
||||||
>
|
|
||||||
> 如果你並非使用`80`端口, 則須在網址後輸入指定端口: http://127.0.0.1:443
|
|
||||||
|
|
||||||
## 更新日誌
|
|
||||||
|
|
||||||
### GrasscutterTools-v1.13
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

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

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

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.9
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.8
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.3
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
新增 [攻擊修改](https://github.com/NotThorny/AttackModifier)、[攻擊注入](https://github.com/snoobi-seggs/AttackInfusedWithItem)、[主角切換元素](https://github.com/Penelopeep/SwitchElementTraveller)等插件指令產生
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.2
|
|
||||||

|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.1
|
|
||||||
- 新增 Gadgets
|
|
||||||
|
|
||||||
### GrasscutterTools-v1.7.0
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
## 工具截圖
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
@ -29,7 +29,7 @@
|
|||||||
<value>10001</value>
|
<value>10001</value>
|
||||||
</setting>
|
</setting>
|
||||||
<setting name="Host" serializeAs="String">
|
<setting name="Host" serializeAs="String">
|
||||||
<value>http://127.0.0.1:443</value>
|
<value>https://127.0.0.1</value>
|
||||||
</setting>
|
</setting>
|
||||||
<setting name="CheckedLastVersion" serializeAs="String">
|
<setting name="CheckedLastVersion" serializeAs="String">
|
||||||
<value />
|
<value />
|
||||||
@ -49,42 +49,6 @@
|
|||||||
<setting name="DefaultMailSender" serializeAs="String">
|
<setting name="DefaultMailSender" serializeAs="String">
|
||||||
<value>GrasscutterTools</value>
|
<value>GrasscutterTools</value>
|
||||||
</setting>
|
</setting>
|
||||||
<setting name="ShopJsonPath" serializeAs="String">
|
|
||||||
<value />
|
|
||||||
</setting>
|
|
||||||
<setting name="MainFormLocation" serializeAs="String">
|
|
||||||
<value>0, 0</value>
|
|
||||||
</setting>
|
|
||||||
<setting name="MainFormSize" serializeAs="String">
|
|
||||||
<value>0, 0</value>
|
|
||||||
</setting>
|
|
||||||
<setting name="BannersJsonPath" serializeAs="String">
|
|
||||||
<value />
|
|
||||||
</setting>
|
|
||||||
<setting name="IsIncludeUID" serializeAs="String">
|
|
||||||
<value>False</value>
|
|
||||||
</setting>
|
|
||||||
<setting name="NavContainerSplitterDistance" serializeAs="String">
|
|
||||||
<value>0</value>
|
|
||||||
</setting>
|
|
||||||
<setting name="ActivityConfigJsonPath" serializeAs="String">
|
|
||||||
<value />
|
|
||||||
</setting>
|
|
||||||
<setting name="ProjectResourcePath" serializeAs="String">
|
|
||||||
<value />
|
|
||||||
</setting>
|
|
||||||
<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>
|
</GrasscutterTools.Properties.Settings>
|
||||||
</userSettings>
|
</userSettings>
|
||||||
</configuration>
|
</configuration>
|
186
Source/GrasscutterTools/Controls/TextBoxXP.cs
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
|
||||||
|
namespace GrasscutterTools.Controls
|
||||||
|
{
|
||||||
|
[ToolboxItem(true)]
|
||||||
|
public class TextBoxXP : TextBox
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得当前进程,以便重绘控件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hWnd"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern IntPtr GetWindowDC(IntPtr hWnd);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||||
|
|
||||||
|
private const int EM_SETCUEBANNER = 0x1501;
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||||
|
private static extern Int32 SendMessage
|
||||||
|
(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 水印文本
|
||||||
|
/// </summary>
|
||||||
|
private string _Watermark = "";
|
||||||
|
|
||||||
|
private float maximum;
|
||||||
|
private float minimum;
|
||||||
|
|
||||||
|
#region 属性
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用热点效果
|
||||||
|
/// </summary>
|
||||||
|
[Category("外观")]
|
||||||
|
[Browsable(true)]
|
||||||
|
[Localizable(true)]
|
||||||
|
[Description("获取或设置输入框水印文本")]
|
||||||
|
[DefaultValue("")]
|
||||||
|
public string Watermark
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this._Watermark;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this._Watermark = value;
|
||||||
|
SendMessage(Handle, EM_SETCUEBANNER, 0, _Watermark);
|
||||||
|
this.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否只能输入数字
|
||||||
|
/// </summary>
|
||||||
|
[Category("行为")]
|
||||||
|
[Browsable(true)]
|
||||||
|
[Description("获取或设置TextBox是否只允许输入数字")]
|
||||||
|
[DefaultValue(false)]
|
||||||
|
public bool DigitOnly { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 转为数值
|
||||||
|
/// </summary>
|
||||||
|
public float Number
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (float.TryParse(Text, out float value))
|
||||||
|
return value;
|
||||||
|
else
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Category("数据")]
|
||||||
|
[Browsable(true)]
|
||||||
|
[DefaultValue(0)]
|
||||||
|
[Description("指示小数点后位数")]
|
||||||
|
public int DecimalPlaces { get; set; }
|
||||||
|
|
||||||
|
[Category("数据")]
|
||||||
|
[Description("获取或设置限制的最大值")]
|
||||||
|
public float Maximum
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return maximum;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
maximum = value;
|
||||||
|
if (minimum > maximum)
|
||||||
|
{
|
||||||
|
minimum = maximum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Category("数据")]
|
||||||
|
[Browsable(true)]
|
||||||
|
[Description("获取或设置限制的最小值")]
|
||||||
|
public float Minimum
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return minimum;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
minimum = value;
|
||||||
|
if (minimum > maximum)
|
||||||
|
{
|
||||||
|
maximum = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion 属性
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public TextBoxXP()
|
||||||
|
: base()
|
||||||
|
{
|
||||||
|
//BorderStyle = BorderStyle.FixedSingle;
|
||||||
|
//Font = Styles.StaticResources.DefaultFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnKeyPress(KeyPressEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnKeyPress(e);
|
||||||
|
// 如果只允许输入数字,则判断输入是否为退格或者数字
|
||||||
|
if (DigitOnly)
|
||||||
|
{
|
||||||
|
//IsNumber:指定字符串中位于指定位置的字符是否属于数字类别
|
||||||
|
//IsPunctuation:指定字符串中位于指定位置的字符是否属于标点符号类别
|
||||||
|
//IsControl:指定字符串中位于指定位置的字符是否属于控制字符类别
|
||||||
|
if (!Char.IsNumber(e.KeyChar) && !Char.IsPunctuation(e.KeyChar) && !Char.IsControl(e.KeyChar))
|
||||||
|
{
|
||||||
|
e.Handled = true; //获取或设置一个值,指示是否处理过System.Windows.Forms.Control.KeyPress事件
|
||||||
|
}
|
||||||
|
else if (Char.IsPunctuation(e.KeyChar) && DecimalPlaces > 0)
|
||||||
|
{
|
||||||
|
if (e.KeyChar == '.')
|
||||||
|
{
|
||||||
|
if (Text.LastIndexOf('.') != -1)
|
||||||
|
{
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnLeave(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnLeave(e);
|
||||||
|
|
||||||
|
if (DigitOnly)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(Text))
|
||||||
|
{
|
||||||
|
if (Number > Maximum)
|
||||||
|
Text = Maximum.ToString("F" + DecimalPlaces);
|
||||||
|
if (Number < Minimum)
|
||||||
|
Text = Minimum.ToString("F" + DecimalPlaces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,9 +14,8 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* 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/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using GrasscutterTools.DispatchServer.Model;
|
using GrasscutterTools.DispatchServer.Model;
|
||||||
@ -24,7 +23,7 @@ using GrasscutterTools.Utils;
|
|||||||
|
|
||||||
namespace GrasscutterTools.DispatchServer
|
namespace GrasscutterTools.DispatchServer
|
||||||
{
|
{
|
||||||
internal static class DispatchServerAPI
|
public static class DispatchServerAPI
|
||||||
{
|
{
|
||||||
public static async Task<ServerStatus> QueryServerStatus(string host)
|
public static async Task<ServerStatus> QueryServerStatus(string host)
|
||||||
{
|
{
|
||||||
|
@ -14,14 +14,13 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* 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/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace GrasscutterTools.DispatchServer.Model
|
namespace GrasscutterTools.DispatchServer.Model
|
||||||
{
|
{
|
||||||
internal class ServerStatus
|
public class ServerStatus
|
||||||
{
|
{
|
||||||
[JsonProperty("playerCount")]
|
[JsonProperty("playerCount")]
|
||||||
public int PlayerCount { get; set; }
|
public int PlayerCount { get; set; }
|
||||||
@ -33,7 +32,7 @@ namespace GrasscutterTools.DispatchServer.Model
|
|||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class ServerStatusResponse
|
public class ServerStatusResponse
|
||||||
{
|
{
|
||||||
[JsonProperty("retcode")]
|
[JsonProperty("retcode")]
|
||||||
public int RetCode { get; set; }
|
public int RetCode { get; set; }
|
||||||
|
@ -1,202 +0,0 @@
|
|||||||
#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();
|
|
||||||
}
|
|
||||||
}
|
|