├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── src └── main ├── kotlin └── srh │ └── shirakana │ └── hoshinoyumemi │ ├── NinnMu.kt │ ├── Plugin.kt │ ├── Work.kt │ ├── command │ ├── Command.kt │ ├── LoliconJson.kt │ └── SaucenaoJson.kt │ └── file │ ├── BaseConfig.kt │ ├── BlackList.kt │ ├── Config.kt │ ├── Course.kt │ ├── Flags.kt │ ├── KouKann.kt │ ├── NlpDisabledGroups.kt │ ├── Saucenao.kt │ ├── Shop.kt │ ├── User.kt │ ├── daixuexi.kt │ ├── eco.kt │ └── replyList.kt └── resources ├── Bg1.png ├── Bg2.png ├── META-INF └── services │ └── net.mamoe.mirai.console.plugin.jvm.JvmPlugin ├── bar.png └── bar_white.png /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff 2 | .idea/ 3 | 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | # IntelliJ 9 | out/ 10 | # mpeltonen/sbt-idea plugin 11 | .idea_modules/ 12 | 13 | # JIRA plugin 14 | atlassian-ide-plugin.xml 15 | 16 | # Compiled class file 17 | *.class 18 | 19 | # Log file 20 | *.log 21 | 22 | # BlueJ files 23 | *.ctxt 24 | 25 | # Package Files # 26 | *.jar 27 | *.war 28 | *.nar 29 | *.ear 30 | *.zip 31 | *.tar.gz 32 | *.rar 33 | 34 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 35 | hs_err_pid* 36 | 37 | *~ 38 | 39 | # temporary files which can be created if a process still has a handle open of a deleted file 40 | .fuse_hidden* 41 | 42 | # KDE directory preferences 43 | .directory 44 | 45 | # Linux trash folder which might appear on any partition or disk 46 | .Trash-* 47 | 48 | # .nfs files are created when an open file is removed but is still being accessed 49 | .nfs* 50 | 51 | # General 52 | .DS_Store 53 | .AppleDouble 54 | .LSOverride 55 | 56 | # Icon must end with two \r 57 | Icon 58 | 59 | # Thumbnails 60 | ._* 61 | 62 | # Files that might appear in the root of a volume 63 | .DocumentRevisions-V100 64 | .fseventsd 65 | .Spotlight-V100 66 | .TemporaryItems 67 | .Trashes 68 | .VolumeIcon.icns 69 | .com.apple.timemachine.donotpresent 70 | 71 | # Directories potentially created on remote AFP share 72 | .AppleDB 73 | .AppleDesktop 74 | Network Trash Folder 75 | Temporary Items 76 | .apdisk 77 | 78 | # Windows thumbnail cache files 79 | Thumbs.db 80 | Thumbs.db:encryptable 81 | ehthumbs.db 82 | ehthumbs_vista.db 83 | 84 | # Dump file 85 | *.stackdump 86 | 87 | # Folder config file 88 | [Dd]esktop.ini 89 | 90 | # Recycle Bin used on file shares 91 | $RECYCLE.BIN/ 92 | 93 | # Windows Installer files 94 | *.cab 95 | *.msi 96 | *.msix 97 | *.msm 98 | *.msp 99 | 100 | # Windows shortcuts 101 | *.lnk 102 | 103 | .gradle 104 | build/ 105 | 106 | # Ignore Gradle GUI config 107 | gradle-app.setting 108 | 109 | # Cache of project 110 | .gradletasknamecache 111 | 112 | **/build/ 113 | 114 | # Common working directory 115 | run/ 116 | 117 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 118 | !gradle-wrapper.jar 119 | 120 | 121 | # Local Test Launch point 122 | src/test/kotlin/RunTerminal.kt 123 | 124 | # Mirai console files with direct bootstrap 125 | /config 126 | /data 127 | /plugins 128 | /bots 129 | 130 | # Local Test Launch Point working directory 131 | /debug-sandbox 132 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2022 FujiwaraShirakana. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published by 637 | the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HoshiniYumemi 2 | 一个基于Mirai的功能性机器人 3 | 4 | ---- 5 | 项目地址:[HoshiniYumemi](https://github.com/FujiwaraShirakana/HoshiniYumemi)\ 6 | 下载地址:[HoshiniYumemiReleases](https://github.com/FujiwaraShirakana/HoshiniYumemi/releases/tag/0.0.1) 7 | ---- 8 | ### 主要功能: 9 | - 好感度 (说是好感度其实是权限等级,好感度为负值则会导致机器人不理你,这时只能通过签到慢慢回复) 10 | - 金币系统 (由于API存在限额,此设定主要是为了防止群友滥用) 11 | - 签到 (签到图像布局抄袭借鉴自真寻Bot) 12 | - 聊天机器人 (不同好感设定有不同的回应词条,若数据中无词条则接入腾讯聊天机器人) 13 | - 腾讯云机器翻译 (需要好感度等级不小于4,金币2*String.Length来使用,好感度等级不低于7级则免金币使用 14 | - 腾讯云OCR (由于开通OCR需要企业认证(貌似),所以目前所有关于这一方面的函数都打了//) 15 | - Saucenao搜图 (需要好感度等级不小于5,金币1000枚才可以使用,好感度等级不小于8级时免金币使用) 16 | - Lolicon搜图 (需要好感度等级不低于4级,金币100*获取数量方可使用,好感度等级不低于7级则免金币使用) 17 | - 黑名单 (将好感度设置为-800并将一切增加好感度的行为变为减少好感度) 18 | - 礼物商店 (给Bot送礼物) 19 | - (TODO)各种其他娱乐型BOT的功能,如小游戏等 20 | ---- 21 | ### 功能详细介绍: 22 | #### 一、好感度系统: 23 | - 1、系统介绍 24 | 25 | 26 | 好感度系统为一切功能的一个前置系统,之所以在前面将好感度称为权限等 27 | 级,是因为好感度决定解锁的机器人功能。 28 | 29 | 好感度的获取途径主要有: 30 | 1、签到;2、和机器人聊天;3、给机器人送礼物;4、在好感度等级足够的 31 | 情况下和机器人进行亲密行为(如贴贴,摸头,叫老婆等);5、夸机器人; 32 | 6、todo 33 | 34 | 失去好感度的主要原因: 35 | 1、辱骂机器人;2、在好感度不足的情况下进行亲密行为(如贴贴,摸头, 36 | 叫老婆等);3、被管理员针对;4、todo 37 | 38 | 好感度上限: 39 | 普通群员上限为800;管理员为900;在data\srh.shirakana.hoshino 40 | yumemi.plugin\HoshinoYumemiUser.yml中SpecialUser中指定的QQ 41 | 用户为1000 42 | 43 | 好感度指令: 44 | @机器人 好感(查看好感) 45 | /usrcmd(我的) kk(查看好感)(查看好感) 46 | /koukann Member Amount(指定Member好感加减) 47 | /koukann Amount(所有群成员好感统一加减) 48 | /好感度 添加/减少/全体添加/全体减少 分别对应以上指令 49 | - 2、好感度存储: 50 | 51 | 52 | ``` 53 | #### data\srh.shirakana.hoshinoyumemi.plugin\HoshinoYumemiKouKann.yml 54 | 55 | # 好感度列表 56 | KouKannList: 57 | 123456: 0.0 58 | 1234567: 1000.0 59 | QQ号码: 好感度数值(Double) 60 | ``` 61 | ---- 62 | #### 二、金币系统: 63 | - 1、系统介绍 64 | 65 | 66 | 目前金币系统仅作为限制功能使用的筹码,以后会出小游戏功能 67 | 68 | 指令: 69 | @机器人 金币(查看金币) 70 | /usrcmd(我的) mon(查看金钱)(查看金币) 71 | /money Member Amount(指定Member金币加减) 72 | /金钱 添加/减少 分别对应以上指令 73 | - 2、金币存储 74 | 75 | ``` 76 | #### data\srh.shirakana.hoshinoyumemi.plugin\HoshinoYumemiMoney.yml 77 | 78 | # 金钱列表 79 | Money: 80 | 12345: 0.0 81 | 123456: 0.0 82 | QQ号码:金币数量 83 | ``` 84 | ---- 85 | #### 三、签到系统: 86 | - 1、系统介绍: 87 | 88 | 89 | 在群内输入签到,或者AT机器人输入签到,即可进行签到,签到会根据抽卡机制 90 | 按照不同段位给予相应的随机好感度以及金币(配图)data\srh.shirakana 91 | .hoshinoyumemi.plugin\HoshinoYumemiUser.yml中bool列表为当日签到状态 92 | 于每日0点重置 93 | ---- 94 | #### 四、聊天系统: 95 | - 1、系统介绍: 96 | 97 | 98 | 需要配置腾讯云APIID和APIKey,配置位置在config\srh.shirakana.hoshino 99 | yumemi.plugin\HoshinoYumemi_TencentCloudApiConfig.yml,一切的聊天 100 | 内容均需要AT机器人触发(特殊动作请注意好感度,可能会扣好感) 101 | 102 | 当机器人受到符合条件的MessageEvent后,优先从data\srh.shirakana.hoshi 103 | noyumemi.plugin\HoshinoYumemiReplyList.yml中读取回复信息,若该列表中 104 | 无响应信息,则使用腾讯云聊天机器人(均为模糊匹配,腾讯云聊天机器人为腾讯 105 | 云自然语言处理中的聊天机器人) 106 | 107 | 聊天机器人指令: 108 | /DataList inputMsg KoukannLevel outputMsg其 109 | 中inputMsg为输入的信息,KoukannLevel为好感度等级(好感度/100).toInt 110 | outputMsg为回复信息(该条回复会被写入上面提到的文件中) 111 | /数据 添加回复/删除回复 分别对应以上指令 112 | 113 | - 2、回复列表存储: 114 | 115 | ``` 116 | #### data\srh.shirakana.hoshinoyumemi.plugin\HoshinoYumemiUser.yml 117 | 118 | # 回复列表 119 | ReplyList: 120 | 1919810: 121 | - 0: 像你这种又屑又臭的人,有在这个群存在的必要吗?!(恼) 122 | - 0: 像你这种又屑又臭的人,为什么还在这个群里呢?(疑惑) 123 | - 0: 像你这种又屑又臭的人,还是赶紧退群罢!(无慈悲) 124 | - 1: 像你这种又屑又臭的人,有在这个群存在的必要吗?!(恼) 125 | - 1: 像你这种又屑又臭的人,为什么还在这个群里呢?(疑惑) 126 | - 1: 像你这种又屑又臭的人,还是赶紧退群罢!(无慈悲) 127 | - 2: 像你这种又屑又臭的人,有在这个群存在的必要吗?!(恼) 128 | - 2: 像你这种又屑又臭的人,为什么还在这个群里呢?(疑惑) 129 | - 2: 像你这种又屑又臭的人,还是赶紧退群罢!(无慈悲) 130 | - 3: 像你这种又屑又臭的人,有在这个群存在的必要吗?!(恼) 131 | - 3: 像你这种又屑又臭的人,为什么还在这个群里呢?(疑惑) 132 | - 3: 像你这种又屑又臭的人,还是赶紧退群罢!(无慈悲) 133 | - 4: 请不要唐突恶臭! 134 | - 4: 为什么总是要这么臭呢? 135 | - 5: 请不要唐突恶臭! 136 | - 5: 为什么总是要这么臭呢? 137 | - 6: 请不要唐突恶臭! 138 | - 6: 为什么总是要这么臭呢? 139 | - 7: 臭死了 140 | - 7: 好臭啊 141 | - 8: 臭死了 142 | - 8: 好臭啊 143 | - 9: 如果是你的话,就算是恶臭的也可以接受 144 | - 9: 但是,我还是更喜欢不臭的你 145 | - 10: 如果是你的话,就算是恶臭的也可以接受 146 | - 10: 但是,我还是更喜欢不臭的你 147 | 114514: 148 | - 0: 像你这种又屑又臭的人,有在这个群存在的必要吗?!(恼) 149 | - 0: 像你这种又屑又臭的人,为什么还在这个群里呢?(疑惑) 150 | - 0: 像你这种又屑又臭的人,还是赶紧退群罢!(无慈悲) 151 | - 1: 像你这种又屑又臭的人,有在这个群存在的必要吗?!(恼) 152 | - 1: 像你这种又屑又臭的人,为什么还在这个群里呢?(疑惑) 153 | - 1: 像你这种又屑又臭的人,还是赶紧退群罢!(无慈悲) 154 | - 2: 像你这种又屑又臭的人,有在这个群存在的必要吗?!(恼) 155 | - 2: 像你这种又屑又臭的人,为什么还在这个群里呢?(疑惑) 156 | - 2: 像你这种又屑又臭的人,还是赶紧退群罢!(无慈悲) 157 | - 3: 像你这种又屑又臭的人,有在这个群存在的必要吗?!(恼) 158 | - 3: 像你这种又屑又臭的人,为什么还在这个群里呢?(疑惑) 159 | - 3: 像你这种又屑又臭的人,还是赶紧退群罢!(无慈悲) 160 | - 4: 请不要唐突恶臭! 161 | - 4: 为什么总是要这么臭呢? 162 | - 5: 请不要唐突恶臭! 163 | - 5: 为什么总是要这么臭呢? 164 | - 6: 请不要唐突恶臭! 165 | - 6: 为什么总是要这么臭呢? 166 | - 7: 臭死了 167 | - 7: 好臭啊 168 | - 8: 臭死了 169 | - 8: 好臭啊 170 | - 9: 如果是你的话,就算是恶臭的也可以接受 171 | - 9: 但是,我还是更喜欢不臭的你 172 | - 10: 如果是你的话,就算是恶臭的也可以接受 173 | - 10: 但是,我还是更喜欢不臭的你 174 | 175 | 文件结构为: 176 | inputMsg1 177 | - KoukannLevel1: outputMsg1 178 | - KoukannLevel1: outputMsg2 179 | - KoukannLevel2: outputMsg1 180 | inputMsg2 181 | - KoukannLevel1: outputMsg1 182 | - KoukannLevel2: outputMsg1 183 | - KoukannLevel2: outputMsg2 184 | 185 | 当同一个KoukannLevel有多个outputMsg时,随机选取其中一个 186 | ``` 187 | ---- 188 | #### 五、各个API的使用: 189 | - 配置文件: 190 | 191 | 192 | 需要配置config\srh.shirakana.hoshinoyumemi.plugin\HoshinoYumemi 193 | _TencentCloudApiConfig.yml中ID和Key 194 | 195 | 需要配置config\srh.shirakana.hoshinoyumemi.plugin\HoshinoYumemi 196 | SaucenaoApiConfig.yml中Key 197 | 198 | 199 | 200 | - 指令: 201 | 202 | 203 | /TCAPI(腾讯云) MT(机器翻译) InputString TargetLang 204 | 其中InputString为要翻译的字符串,空格用下划线"_"代替,TargetLang为 205 | 目标语言,需要使用简写,如中文“zh”;日语“jp”;英语“en” 206 | /eroImage(涩图) g(发几张) Tag Amount 207 | 获取Amount张(小于等于5)lolicon涩图,不支持R18,发送为转发消息模式 208 | 30秒撤回,Tag可使用rand来代表随机Tag 209 | /eroImage(涩图) s(搜索) Image 210 | 使用Saucenao搜索指定图片 211 | ---- 212 | #### 六、礼物商店 213 | - 指令: 214 | 215 | 216 | /usrcmd(我的) giftlist(列出礼物列表) 217 | /usrcmd(我的) gift ID(给机器人送指定ID的礼物) 218 | /DataList Name Cost(加减名为Name售价Cost的商品) 219 | /我的 礼物列表/送礼物 220 | /数据 添加商品/删除商品 221 | 机器人好感度获取为物品价格/1000 222 | - 文件: 223 | 224 | 225 | ``` 226 | #### data\srh.shirakana.hoshinoyumemi.plugin\HoshinoYumemiShop 227 | 228 | # 商店列表 229 | Shop: 230 | - 古河面包: 1000.0 231 | - 商品名: 售价 232 | ``` 233 | ---- 234 | #### 七、其他指令 235 | - 黑名单:/KouKann Member(将指定群员添加/移除出黑名单> 236 | - @机器人 睡吧(关闭插件功能) 237 | - @机器人 起床吧(开启插件功能) 238 | ---- 239 | #### 八、打工和学位 240 | 241 | - 介绍: 242 | 243 | 244 | 打工功能,不过与其他娱乐机器人不同,想要打工,必须取得相应专业的学位 245 | 而学位可以通过考试获得,考试的题目需机器人的管理者自行建库。 246 | 指令: 247 | /AdmCmd addTest 248 | #为Specialize专业添加Question问题,答案为Answer(专业不存在则创建) 249 | /AdmCmd addWork 250 | #添加requiredSpecialize专业对应的工作,基础工资为reward(需要存在 251 | 专业“requiredSpecialize”(上一个指令创建) 252 | /AdmCmd delTest 253 | /AdmCmd delWork 254 | #下面两个为删除相应内容 255 | /usrcmd LS 256 | #查看所有存在的专业 257 | /usrcmd mysp 258 | #查看自己的专业及学位 259 | /usrcmd giveupmysp 260 | #放弃自己的学位 261 | /usrcmd jointest 262 | #参加指定专业“Specialize”的考试 263 | /usrcmd exittest 264 | #退出当前考试 265 | /我的 参加考试/退出考试/有什么专业/我的专业/放弃学位 266 | - 文件: 267 | 268 | 269 | ``` 270 | #### data\srh.shirakana.hoshinoyumemi.plugin\HoshinoYumemiCourse 271 | 272 | # 题目 273 | Course: 274 | 数学: 275 | - 1+1=?: 2 276 | - 题目: 答案 277 | 专业: 278 | - 题目: 答案 279 | 280 | 还有两个json,存储用户和工作() 281 | ``` 282 | 283 | 284 | #### 更新日志: 285 | ##### 6月10日- 286 | 1、名称显示修复 287 | 2、降低了聊天获取的好感度 288 | 3、降低了签到获取的金币 289 | 4、打工、学位系统实装并进入测试 290 | ##### 6月14日- 291 | 1、标准化了试题的格式 292 | 2、修复了考试的几个BUG 293 | ##### 6月29日- 294 | 1、添加了中文指令 295 | 2、腾讯云NLP聊天机器人开关(使用/AdmCmd Disable add/del 群号) 296 | 群号为0时则操作机器人所在的所有群 -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | val kotlinVersion = "1.5.30" 3 | kotlin("jvm") version kotlinVersion 4 | kotlin("plugin.serialization") version kotlinVersion 5 | 6 | id("net.mamoe.mirai-console") version "2.9.2" 7 | } 8 | 9 | group = "srh.shirakana.hoshinoyumemi" 10 | version = "0.0.3" 11 | 12 | repositories { 13 | maven("https://maven.aliyun.com/repository/public") 14 | mavenCentral() 15 | } 16 | dependencies { 17 | implementation("com.tencentcloudapi:tencentcloud-sdk-java:4.0.11") 18 | implementation("com.alibaba:fastjson:2.0.7") 19 | implementation("org.xerial:sqlite-jdbc:3.36.0.3") 20 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PriesiaMioShirakana/HoshinoYumemi/f3584404813ae5c2ae44c29d17e399de93a4458a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenLocal() 4 | mavenCentral() 5 | gradlePluginPortal() 6 | } 7 | } 8 | rootProject.name = "HoshiniYumemi" -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/NinnMu.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi 2 | 3 | import com.alibaba.fastjson.JSON 4 | import com.alibaba.fastjson.JSONObject 5 | import com.alibaba.fastjson.serializer.SerializerFeature 6 | import com.tencentcloudapi.common.Credential 7 | import com.tencentcloudapi.common.exception.TencentCloudSDKException 8 | import com.tencentcloudapi.common.profile.ClientProfile 9 | import com.tencentcloudapi.common.profile.HttpProfile 10 | import com.tencentcloudapi.nlp.v20190408.NlpClient 11 | import com.tencentcloudapi.nlp.v20190408.models.ChatBotRequest 12 | import com.tencentcloudapi.nlp.v20190408.models.TextSimilarityRequest 13 | import kotlinx.coroutines.Dispatchers 14 | import kotlinx.coroutines.launch 15 | import kotlinx.coroutines.withContext 16 | import kotlinx.serialization.ExperimentalSerializationApi 17 | import kotlinx.serialization.decodeFromString 18 | import kotlinx.serialization.encodeToString 19 | import kotlinx.serialization.json.Json 20 | import net.mamoe.mirai.contact.isAdministrator 21 | import net.mamoe.mirai.contact.isOwner 22 | import net.mamoe.mirai.event.EventHandler 23 | import net.mamoe.mirai.event.SimpleListenerHost 24 | import net.mamoe.mirai.event.events.* 25 | import net.mamoe.mirai.message.data.At 26 | import net.mamoe.mirai.message.data.PlainText 27 | import net.mamoe.mirai.message.data.buildMessageChain 28 | import net.mamoe.mirai.utils.ExternalResource.Companion.uploadAsImage 29 | import srh.shirakana.hoshinoyumemi.command.HoshinoYumemiKouKannCommand.buildSignImage 30 | import srh.shirakana.hoshinoyumemi.file.* 31 | import java.io.File 32 | import java.math.RoundingMode 33 | import java.nio.charset.StandardCharsets.UTF_8 34 | import java.nio.file.Files 35 | import java.nio.file.Paths 36 | import java.util.* 37 | 38 | 39 | var userJobs = BotJobs() 40 | var userS = UserWorks() 41 | 42 | public object ShirakanaEventListener : SimpleListenerHost() { 43 | @EventHandler 44 | @OptIn(ExperimentalSerializationApi::class) 45 | internal suspend fun BotOnlineEvent.handle0() { 46 | val newDire = File("Yumemi") 47 | if(!newDire.exists()){ 48 | newDire.mkdir() 49 | } 50 | val userDataFile = File("data/srh.shirakana.hoshinoyumemi.plugin/Users.json") 51 | val jobsDataFile = File("data/srh.shirakana.hoshinoyumemi.plugin/Jobs.json") 52 | if(!userDataFile.exists()) withContext(Dispatchers.IO) { 53 | userDataFile.createNewFile() 54 | userDataFile.writeText("{}") 55 | } 56 | if(!jobsDataFile.exists()) withContext(Dispatchers.IO) { 57 | jobsDataFile.createNewFile() 58 | jobsDataFile.writeText("{}") 59 | } 60 | userS = Json.decodeFromString(String(withContext(Dispatchers.IO) { 61 | Files.readAllBytes(Paths.get(userDataFile.path)) 62 | },UTF_8)) 63 | userJobs = Json.decodeFromString(String(withContext(Dispatchers.IO) { 64 | Files.readAllBytes(Paths.get(jobsDataFile.path)) 65 | },UTF_8)) 66 | for(group in bot.groups){ 67 | for(member in group.members){ 68 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] ==null){ 69 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = 0.0 70 | } 71 | if(HoshinoYumemiUser.HoshinoYumemiNoUser[member.id]==null){ 72 | HoshinoYumemiUser.HoshinoYumemiNoUser[member.id] = false 73 | } 74 | if(HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id]==null){ 75 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id] = 0.0 76 | } 77 | if(userS[member.id]==null){ 78 | userS.userdata.add(UserWorks.UserWorksData(member.id,0,"null",false,"",false,"")) 79 | } 80 | } 81 | } 82 | 83 | val t1 = Timer() 84 | val startCalendar = Calendar.getInstance() 85 | startCalendar[Calendar.HOUR_OF_DAY] = 0 // 控制时 86 | startCalendar[Calendar.MINUTE] = 0 // 控制分 87 | startCalendar[Calendar.SECOND] = 0 // 控制秒 88 | val startTime = startCalendar.time 89 | t1.scheduleAtFixedRate(object : TimerTask() { 90 | override fun run() { 91 | for(key in HoshinoYumemiUser.HoshinoYumemiNoUser.keys){ 92 | HoshinoYumemiUser.HoshinoYumemiNoUser[key] = false 93 | } 94 | for(userTmp in userS.userdata){ 95 | userTmp.state=false 96 | } 97 | val dire = File("Yumemi") 98 | if (dire.exists()){ 99 | for(file in dire.listFiles()!!){ 100 | file.delete() 101 | } 102 | } 103 | 104 | val userSJson = Json.encodeToString(userS) 105 | val userJobsJson = Json.encodeToString(userJobs) 106 | val jsonObjectUserS: JSONObject = JSONObject.parseObject(userSJson) 107 | val formatStrUserS: String = JSON.toJSONString( 108 | jsonObjectUserS, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, 109 | SerializerFeature.WriteDateUseDateFormat 110 | ) 111 | userDataFile.writeText(formatStrUserS) 112 | val jsonObjectUserJobs: JSONObject = JSONObject.parseObject(userJobsJson) 113 | val formatStrUserJobs: String = JSON.toJSONString( 114 | jsonObjectUserJobs, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, 115 | SerializerFeature.WriteDateUseDateFormat 116 | ) 117 | jobsDataFile.writeText(formatStrUserJobs) 118 | 119 | println("好感度及每日状态重载完毕") 120 | } 121 | }, startTime, 1000*24*60*60) 122 | println("开启定时任务:好感度及每日状态重载") 123 | } 124 | 125 | @EventHandler 126 | @OptIn(ExperimentalSerializationApi::class) 127 | internal suspend fun BotOfflineEvent.handle0() { 128 | val userDataFile = File("data/srh.shirakana.hoshinoyumemi.plugin/Users.json") 129 | val jobsDataFile = File("data/srh.shirakana.hoshinoyumemi.plugin/Jobs.json") 130 | 131 | val userSJson = Json.encodeToString(userS) 132 | val userJobsJson = Json.encodeToString(userJobs) 133 | 134 | val jsonObjectUserS: JSONObject = JSONObject.parseObject(userSJson) 135 | val formatStrUserS: String = JSON.toJSONString( 136 | jsonObjectUserS, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, 137 | SerializerFeature.WriteDateUseDateFormat 138 | ) 139 | userDataFile.writeText(formatStrUserS) 140 | 141 | val jsonObjectUserJobs: JSONObject = JSONObject.parseObject(userJobsJson) 142 | val formatStrUserJobs: String = JSON.toJSONString( 143 | jsonObjectUserJobs, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, 144 | SerializerFeature.WriteDateUseDateFormat 145 | ) 146 | jobsDataFile.writeText(formatStrUserJobs) 147 | } 148 | @EventHandler 149 | internal suspend fun MemberJoinEvent.handle0() { 150 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] ==null){ 151 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = 0.0 152 | } 153 | if(HoshinoYumemiUser.HoshinoYumemiNoUser[member.id]==null){ 154 | HoshinoYumemiUser.HoshinoYumemiNoUser[member.id] = false 155 | } 156 | if(HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id]==null){ 157 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id] = 0.0 158 | } 159 | } 160 | @EventHandler 161 | internal suspend fun MemberLeaveEvent.handle0() { 162 | group.sendMessage(member.nick + " 离开了我们") 163 | for(groupTmp in bot.groups){ 164 | if(groupTmp.members.contains(member.id)){ 165 | return 166 | } 167 | } 168 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann.remove(member.id) 169 | HoshinoYumemiUser.HoshinoYumemiNoUser.remove(member.id) 170 | HoshinoYumemiMoney.HoshinoYumemiNoMoney.remove(member.id) 171 | } 172 | @EventHandler 173 | internal suspend fun GroupMessageEvent.handle0() { 174 | if (message.contentToString() == "签到" || (message.contentToString() 175 | .contains("签到") && message.contentToString().contains(At(bot).contentToString())) 176 | ) { 177 | if (!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch) { 178 | return 179 | } 180 | var kouKanAddValue = 0.0 181 | var moneyAddValue = 0.0 182 | if (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] == null) { 183 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = 0.0 184 | } 185 | if (HoshinoYumemiUser.HoshinoYumemiNoUser[sender.id] == null) { 186 | HoshinoYumemiUser.HoshinoYumemiNoUser[sender.id] = false 187 | } 188 | if (HoshinoYumemiMoney.HoshinoYumemiNoMoney[sender.id] == null) { 189 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[sender.id] = 0.0 190 | } 191 | if (HoshinoYumemiUser.HoshinoYumemiNoUser[sender.id] == true) { 192 | val msgChainTmp = buildMessageChain { 193 | +At(sender) 194 | +File("Yumemi/" + sender.id.toString() + ".png").uploadAsImage(group) 195 | +PlainText("\n你今日已经签到过,这是你的本日数据") 196 | } 197 | group.sendMessage(msgChainTmp) 198 | return 199 | } 200 | launch { 201 | if (HoshinoYumemiUser.HoshinoYumemiNoUser[sender.id] == false) { 202 | HoshinoYumemiUser.HoshinoYumemiNoUser[sender.id] = true 203 | val rate = (0..10000).random() 204 | if (rate > 9990) { 205 | moneyAddValue = ((1500000..2000000).random().toDouble() / 100000.0) 206 | kouKanAddValue = (30000..50000).random().toDouble() / 10000.0 207 | } else if (rate > 9900) { 208 | moneyAddValue = ((1000000..1500000).random().toDouble() / 100000.0) 209 | kouKanAddValue = (15000..30000).random().toDouble() / 10000.0 210 | } else if (rate > 9000) { 211 | moneyAddValue = ((500000..1000000).random().toDouble() / 100000.0) 212 | kouKanAddValue = (10000..15000).random().toDouble() / 10000.0 213 | } else if (rate > 6000) { 214 | moneyAddValue = ((100000..500000).random().toDouble() / 100000.0) 215 | kouKanAddValue = (6000..10000).random().toDouble() / 10000.0 216 | } else { 217 | moneyAddValue = ((100..100000).random().toDouble() / 100000.0) 218 | kouKanAddValue = (1..6000).random().toDouble() / 10000.0 219 | } 220 | if (HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(sender.id)) { 221 | moneyAddValue = 0.0 222 | kouKanAddValue *= -1.0 223 | } 224 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[sender.id] = 225 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[sender.id]!! + moneyAddValue 226 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = 227 | kouKanAddValue + HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! 228 | if (HoshinoYumemiUser.HoshinoYumemiNoSpecialUser.contains(sender.id)) { 229 | if (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! > 1000.0) { 230 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = 1000.0 231 | } 232 | } else if (sender.isOwner() || sender.isAdministrator()) { 233 | if (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! > 900.0) { 234 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = 900.0 235 | } 236 | } else { 237 | if (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! > 800.0) { 238 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = 800.0 239 | } 240 | } 241 | if (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! < -800.0) { 242 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = -800.0 243 | } 244 | } 245 | val msgChainTmp = buildMessageChain { 246 | +At(sender) 247 | +buildSignImage(sender, kouKanAddValue, moneyAddValue).uploadAsImage(group) 248 | } 249 | group.sendMessage(msgChainTmp) 250 | } 251 | } 252 | } 253 | @EventHandler 254 | internal suspend fun GroupMessageEvent.handle1() { 255 | if(message.contains(At(bot))){ 256 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 257 | return 258 | } 259 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(sender.id)){ 260 | group.sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName+"非常讨厌你") 261 | return 262 | } 263 | if(message.contentToString().contains("签到")){ 264 | return 265 | } 266 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! <0){ 267 | group.sendMessage("哼,不理你了") 268 | return 269 | } 270 | if(userS[sender.id]!!.testState){ 271 | if(message.contentToString().replace(At(bot).contentToString()+" ","").replace(At(bot).contentToString()+" ","").replace(At(bot).contentToString(),"")==HoshinoYumemiCourse.HoshinoYumemiNoCourses[userS[sender.id]!!.testSpecialize]!!.find{it.keys.contains(userS[sender.id]!!.testQuest)}!![userS[sender.id]!!.testQuest]){ 272 | if(userS[sender.id]!!.specialized==userS[sender.id]!!.testSpecialize) { 273 | if (userS[sender.id]!!.degree < 20) { 274 | userS[sender.id]!!.degree++ 275 | subject.sendMessage("恭喜你,答对了,等级增加") 276 | } 277 | }else{ 278 | subject.sendMessage("恭喜你,答对了") 279 | } 280 | }else{ 281 | subject.sendMessage(message.contentToString().replace(At(bot).contentToString(),"")+"不是正确的答案或格式错误,很遗憾,答错了") 282 | } 283 | userS[sender.id]!!.testState=false 284 | userS[sender.id]!!.testQuest="" 285 | userS[sender.id]!!.testSpecialize="" 286 | return 287 | } 288 | if(message.contentToString().replace(At(bot).contentToString(),"").replace(" ","")=="好感"||message.contentToString().contains("查看好感")||message.contentToString().contains("我的好感")){ 289 | val msgChain = buildMessageChain { 290 | +At(sender) 291 | +PlainText("您当前的好感度是:"+HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!!.toBigDecimal().setScale(2, RoundingMode.HALF_UP).toString()) 292 | } 293 | group.sendMessage(msgChain) 294 | return 295 | } 296 | if(message.contentToString().replace(At(bot).contentToString(),"").replace(" ","")=="金币"||message.contentToString().contains("查看金币")){ 297 | val msgChain = buildMessageChain { 298 | +At(sender) 299 | +PlainText("您当前的金币数是:"+HoshinoYumemiMoney.HoshinoYumemiNoMoney[sender.id]!!.toBigDecimal().setScale(2, RoundingMode.HALF_UP).toString()) 300 | } 301 | group.sendMessage(msgChain) 302 | return 303 | } 304 | if(message.contentToString().replace(At(bot).contentToString(),"").replace(" ","")=="打工"){ 305 | userS[sender.id]?.work()?.let { group.sendMessage(it) } 306 | return 307 | } 308 | for(key in HoshinoYumemiReplyList.HoshinoYumemiNoReplyList.keys){ 309 | if(message.contentToString().contains(key)){ 310 | val kouKannValueThis = HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!!.div(100.0).toLong() 311 | if(HoshinoYumemiReplyList.HoshinoYumemiNoReplyList[key]!!.find{kouKannValueThis in it.keys}==null){ 312 | return 313 | } 314 | val tmpSetOfMap = mutableSetOf>() 315 | for (map in HoshinoYumemiReplyList.HoshinoYumemiNoReplyList[key]!!){ 316 | if(map.keys.contains(kouKannValueThis)) 317 | tmpSetOfMap.add(map) 318 | } 319 | val msgTmpAmount = tmpSetOfMap.size 320 | val rand = msgTmpAmount.let { Random().nextInt(it) } 321 | val msgTmp = tmpSetOfMap.elementAt(rand)[kouKannValueThis] 322 | val msgChain = buildMessageChain { 323 | +At(sender) 324 | +PlainText(" $msgTmp") 325 | } 326 | group.sendMessage(msgChain) 327 | return 328 | } 329 | } 330 | if(!HoshinoYumemiTencentCloudDisabledGroups.HoshinoYumemiNoTencentCloudDisabledGroups.contains(subject.id)) { 331 | try { 332 | val cred = Credential( 333 | HoshinoYumemiTencentCloudApiConfig.HoshinoYumemiSecretId, 334 | HoshinoYumemiTencentCloudApiConfig.HoshinoYumemiSecretKey 335 | ) 336 | val httpProfile = HttpProfile() 337 | httpProfile.endpoint = "nlp.tencentcloudapi.com" 338 | val clientProfile = ClientProfile() 339 | clientProfile.httpProfile = httpProfile 340 | val client = NlpClient(cred, "ap-guangzhou", clientProfile) 341 | val req = ChatBotRequest() 342 | req.flag = 0L 343 | val msgInput = message.contentToString().replace(At(bot).contentToString(), "") 344 | req.query = msgInput 345 | val resp = client.ChatBot(req) 346 | if (resp.reply.contains("喜欢")) { 347 | val msgChain = buildMessageChain { 348 | +At(sender) 349 | +PlainText(" ...") 350 | } 351 | group.sendMessage(msgChain) 352 | return 353 | } 354 | val msgChain = buildMessageChain { 355 | +At(sender) 356 | +PlainText( 357 | " " + resp.reply.replace("腾讯小龙女", HoshinoYumemiConfig.HoshinoYumemiNoName) 358 | .replace("小龙女", HoshinoYumemiConfig.HoshinoYumemiNoName) 359 | .replace("姑姑", HoshinoYumemiConfig.HoshinoYumemiNoName) 360 | ) 361 | } 362 | group.sendMessage(msgChain) 363 | } catch (e: TencentCloudSDKException) { 364 | group.sendMessage(e.toString()) 365 | } 366 | } 367 | } 368 | } 369 | @EventHandler 370 | internal suspend fun GroupMessageEvent.handle2() { 371 | if(message.contains(At(bot))){ 372 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 373 | return 374 | } 375 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! <0){ 376 | return 377 | } 378 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(sender.id)){ 379 | return 380 | } 381 | var respTmp = false; 382 | val msgTemp = message.contentToString().replace(At(bot).contentToString(),"") 383 | if(msgTemp.contains("签到")){ 384 | return 385 | } 386 | try { 387 | val cred = Credential(HoshinoYumemiTencentCloudApiConfig.HoshinoYumemiSecretId, HoshinoYumemiTencentCloudApiConfig.HoshinoYumemiSecretKey) 388 | val httpProfile = HttpProfile() 389 | httpProfile.endpoint = "nlp.tencentcloudapi.com" 390 | val clientProfile = ClientProfile() 391 | clientProfile.httpProfile = httpProfile 392 | val client = NlpClient(cred, "ap-guangzhou", clientProfile) 393 | val req = TextSimilarityRequest() 394 | val targetText1 = arrayOf("傻逼", "笨蛋") 395 | req.srcText = msgTemp; 396 | req.targetText = targetText1; 397 | val resp = client.TextSimilarity(req) 398 | if(resp.similarity[0].score>0.9||resp.similarity[1].score>0.85){ 399 | respTmp = true 400 | } 401 | } catch (e: TencentCloudSDKException) { 402 | println(e.toString()) 403 | } 404 | if(msgTemp.contains("抱抱")||msgTemp.contains("贴贴")||msgTemp.contains("摸头")||msgTemp.contains("摸一摸头")||msgTemp.contains("老婆")||msgTemp.contains("达令")||msgTemp.contains("亲亲")||msgTemp.contains("亲一下")||msgTemp.contains("亲一口")||msgTemp.contains("喜欢你")){ 405 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! <500.0){ 406 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! - (200..1000).random().toDouble()/10000.0 407 | }else if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! >700.0){ 408 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! + (200..2000).random().toDouble()/10000.0 409 | } 410 | }else if(msgTemp.contains("爬")||msgTemp.contains("笨蛋")||msgTemp.contains("傻逼")||respTmp){ 411 | if(HoshinoYumemiUser.HoshinoYumemiNoSpecialUser.contains(sender.id)){ 412 | return 413 | }else{ 414 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! - (200..1000).random().toDouble()/500.0 415 | } 416 | }else if(msgTemp.contains("你真强")||msgTemp.contains("你真棒")||msgTemp.contains("你真厉害")||msgTemp.contains("谢谢")){ 417 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!!<0){ 418 | return 419 | } 420 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! + (200..1000).random().toDouble()/10000.0 421 | }else{ 422 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] = HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]!! + (200..1000).random().toDouble()/20000.0 423 | } 424 | if(HoshinoYumemiUser.HoshinoYumemiNoSpecialUser.contains(sender.id)){ 425 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] !!> 1000.0){ 426 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]=1000.0 427 | } 428 | } else if(sender.isOwner()||sender.isAdministrator()){ 429 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] !!> 900.0){ 430 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]=900.0 431 | } 432 | }else{ 433 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] !!> 800.0){ 434 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]=800.0 435 | } 436 | } 437 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id] !!< -800.0){ 438 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[sender.id]= -800.0 439 | } 440 | } 441 | } 442 | @EventHandler 443 | internal suspend fun GroupMessageEvent.handle3() { 444 | if(message.contains(At(bot))) { 445 | if (HoshinoYumemiUser.HoshinoYumemiNoSpecialUser.contains(sender.id)||sender.isAdministrator()||sender.isOwner()) { 446 | if(message.contentToString().contains("睡吧")){ 447 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 448 | group.sendMessage("ZZZZZZZZZZZZ") 449 | } 450 | group.sendMessage("那么"+HoshinoYumemiConfig.HoshinoYumemiNoName+"就要休息了") 451 | HoshinoYumemiSwitch.HoshinoYumemiNoSwitch = false 452 | }else if(message.contentToString().contains("起床了")){ 453 | if(HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 454 | group.sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName+"没睡啊") 455 | } 456 | group.sendMessage("呜呜呜,还想多睡一会") 457 | HoshinoYumemiSwitch.HoshinoYumemiNoSwitch = true 458 | } 459 | } 460 | } 461 | } 462 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/Plugin.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi 2 | 3 | import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register 4 | import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregister 5 | import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription 6 | import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin 7 | import net.mamoe.mirai.event.globalEventChannel 8 | import net.mamoe.mirai.event.registerTo 9 | import net.mamoe.mirai.utils.info 10 | import srh.shirakana.hoshinoyumemi.HoshiniYumemi.reload 11 | import srh.shirakana.hoshinoyumemi.command.* 12 | import srh.shirakana.hoshinoyumemi.file.* 13 | 14 | object HoshiniYumemi : KotlinPlugin( 15 | JvmPluginDescription( 16 | id = "srh.shirakana.hoshinoyumemi.plugin", 17 | name = "功能性机器人", 18 | version = "0.0.3", 19 | ) { 20 | author("藤原白叶") 21 | } 22 | ) { 23 | override fun onEnable() { 24 | HoshinoYumemiTencentCloudDisabledGroups.reload() 25 | HoshinoYumemiTencentCloudApiConfig.reload() 26 | HoshinoYumemiReplyList.reload() 27 | HoshinoYumemiKouKann.reload() 28 | HoshinoYumemiUser.reload() 29 | HoshinoYumemiMoney.reload() 30 | HoshinoYumemiBlackList.reload() 31 | HoshinoYumemiSwitch.reload() 32 | HoshinoYumemiSaucenaoApiConfig.reload() 33 | HoshinoYumemiShop.reload() 34 | HoshinoYumemiConfig.reload() 35 | HoshinoYumemiCourse.reload() 36 | 37 | ShirakanaEventListener.registerTo(globalEventChannel()) 38 | 39 | HoshinoYumemiSeTuCommand.register() 40 | HoshinoYumemiKouKannCommand.register() 41 | HoshinoYumemiMoneyCommand.register() 42 | HoshinoYumemiReplyListCommand.register() 43 | HoshinoYumemiTencentCloudAPI.register() 44 | HoshinoYumemiUserCommand.register() 45 | HoshinoYumemiWorkCommand.register() 46 | 47 | logger.info { "Plugin 功能性机器人 loaded" } 48 | } 49 | 50 | override fun onDisable() { 51 | HoshinoYumemiKouKannCommand.unregister() 52 | HoshinoYumemiMoneyCommand.unregister() 53 | HoshinoYumemiReplyListCommand.unregister() 54 | HoshinoYumemiTencentCloudAPI.unregister() 55 | HoshinoYumemiUserCommand.unregister() 56 | HoshinoYumemiSeTuCommand.unregister() 57 | HoshinoYumemiWorkCommand.unregister() 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/Work.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi 2 | 3 | import kotlinx.serialization.Serializable 4 | import net.mamoe.mirai.message.data.At 5 | import net.mamoe.mirai.message.data.MessageChain 6 | import net.mamoe.mirai.message.data.PlainText 7 | import net.mamoe.mirai.message.data.buildMessageChain 8 | import srh.shirakana.hoshinoyumemi.file.HoshinoYumemiMoney 9 | import kotlin.math.E 10 | import kotlin.math.ln 11 | 12 | @Serializable 13 | data class UserWorks(val userdata : MutableList = mutableListOf()){ 14 | 15 | @Serializable 16 | data class UserWorksData( 17 | val id: Long, 18 | var degree: Int, 19 | var specialized: String, 20 | var state: Boolean, 21 | var testQuest: String, 22 | var testState: Boolean, 23 | var testSpecialize:String 24 | ){ 25 | public fun work():MessageChain{ 26 | if(this.state){ 27 | return buildMessageChain { 28 | +At(id) 29 | +PlainText("你今天已经工作过了") 30 | } 31 | } 32 | if(this.specialized=="null"){return buildMessageChain { 33 | +At(id) 34 | +PlainText("你不具备任何专业的学位") 35 | }} 36 | if(userJobs[specialized]==null){ 37 | return buildMessageChain { 38 | +At(id) 39 | +PlainText("该专业无对应的工作") 40 | } 41 | } 42 | this.state = true 43 | val moneyAddValue = userJobs[specialized]!!.reward*ln(degree * E) 44 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[this.id] = 45 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[this.id]!! + moneyAddValue 46 | return buildMessageChain { 47 | +At(id) 48 | +PlainText("你工作了一天,赚取了${moneyAddValue}报酬") 49 | } 50 | } 51 | } 52 | public operator fun get(index :Long):UserWorksData?{ 53 | return this.userdata.find{it.id==index} 54 | } 55 | } 56 | 57 | @Serializable 58 | data class BotJobs(val job : MutableList = mutableListOf()){ 59 | 60 | @Serializable 61 | data class JobsBot( 62 | val requiredSpecialized :String = "", 63 | var reward: Double = 0.0 64 | ){ 65 | } 66 | public operator fun get(index :String):JobsBot?{ 67 | return this.job.find{it.requiredSpecialized==index} 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/command/Command.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.command 2 | 3 | import com.alibaba.fastjson.JSON 4 | import com.alibaba.fastjson.JSONObject 5 | import com.alibaba.fastjson.serializer.SerializerFeature 6 | import com.tencentcloudapi.common.Credential 7 | import com.tencentcloudapi.common.exception.TencentCloudSDKException 8 | import com.tencentcloudapi.common.profile.ClientProfile 9 | import com.tencentcloudapi.common.profile.HttpProfile 10 | import com.tencentcloudapi.tmt.v20180321.TmtClient 11 | import com.tencentcloudapi.tmt.v20180321.models.TextTranslateRequest 12 | import kotlinx.coroutines.* 13 | import kotlinx.serialization.ExperimentalSerializationApi 14 | import kotlinx.serialization.Serializable 15 | import kotlinx.serialization.decodeFromString 16 | import kotlinx.serialization.encodeToString 17 | import kotlinx.serialization.json.Json 18 | import net.mamoe.mirai.console.command.CommandSender 19 | import net.mamoe.mirai.console.command.CompositeCommand 20 | import net.mamoe.mirai.console.util.ConsoleExperimentalApi 21 | import net.mamoe.mirai.contact.* 22 | import net.mamoe.mirai.message.data.* 23 | import net.mamoe.mirai.message.data.Image.Key.queryUrl 24 | import net.mamoe.mirai.utils.ExternalResource 25 | import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource 26 | import net.mamoe.mirai.utils.ExternalResource.Companion.uploadAsImage 27 | import okhttp3.OkHttpClient 28 | import okhttp3.Request 29 | import srh.shirakana.hoshinoyumemi.BotJobs 30 | import srh.shirakana.hoshinoyumemi.HoshiniYumemi 31 | import srh.shirakana.hoshinoyumemi.file.* 32 | import srh.shirakana.hoshinoyumemi.userJobs 33 | import srh.shirakana.hoshinoyumemi.userS 34 | import java.awt.Color 35 | import java.awt.Font 36 | import java.awt.image.BufferedImage 37 | import java.io.File 38 | import java.math.RoundingMode 39 | import java.net.URL 40 | import java.util.* 41 | import javax.imageio.ImageIO 42 | 43 | object HoshinoYumemiKouKannCommand : CompositeCommand( 44 | HoshiniYumemi, "KouKann","好感度", 45 | description = "操作好感度", 46 | ){ 47 | 48 | @JvmStatic 49 | val KouKanBar: BufferedImage = ImageIO.read(HoshinoYumemiKouKannCommand::class.java.classLoader.getResource("bar.png")) 50 | @JvmStatic 51 | val KouKanBarEmpty: BufferedImage = ImageIO.read(HoshinoYumemiKouKannCommand::class.java.classLoader.getResource("bar_white.png")) 52 | @JvmStatic 53 | val BgImage1: BufferedImage = ImageIO.read(HoshinoYumemiKouKannCommand::class.java.classLoader.getResource("Bg1.png")) 54 | @JvmStatic 55 | val BgImage2: BufferedImage = ImageIO.read(HoshinoYumemiKouKannCommand::class.java.classLoader.getResource("Bg2.png")) 56 | 57 | fun buildSignImage (target : Member,kouKanAdd : Double,moneyAdd : Double) : ExternalResource { 58 | val newImg = BufferedImage(1280, 610, BufferedImage.TYPE_4BYTE_ABGR) 59 | val graphics = newImg.createGraphics() 60 | graphics.color = Color(0,0,0) 61 | val rate = (1..2).random() 62 | val kouKanLevel = (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[target.id]!! / 100.0).toLong() 63 | val kouKanValue = HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[target.id]!!.toLong()%100L 64 | graphics.drawImage(ImageIO.read(URL(target.avatarUrl)), 87, 314,184,184, null) 65 | graphics.drawImage(KouKanBarEmpty, 422, 390,320,32, null) 66 | graphics.drawImage(KouKanBar, 422, 390,(3.2*kouKanValue).toInt(),32, null) 67 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[target.id]!!>99||kouKanValue == 0L){ 68 | graphics.drawImage(KouKanBar, 422, 390,320,32, null) 69 | } 70 | if(rate == 1){ 71 | graphics.drawImage(BgImage1, 0, 0, null) 72 | }else{ 73 | graphics.drawImage(BgImage2, 0, 0, null) 74 | } 75 | graphics.font = Font("楷体", Font.PLAIN ,18) 76 | val fixedOffsetY = graphics.fontMetrics.ascent - (graphics.fontMetrics.height / 2 - 18 / 2) 77 | graphics.drawString(kouKanLevel.toString(),536,438+fixedOffsetY) 78 | if(kouKanLevel==10L){ 79 | graphics.drawString("${HoshinoYumemiConfig.HoshinoYumemiNoName}对你的态度:[誓约/爱]",438,470+fixedOffsetY) 80 | }else if(kouKanLevel==9L){ 81 | graphics.drawString("${HoshinoYumemiConfig.HoshinoYumemiNoName}对你的态度:[至交]",438,470+fixedOffsetY) 82 | }else if(kouKanLevel>7){ 83 | graphics.drawString("${HoshinoYumemiConfig.HoshinoYumemiNoName}对你的态度:[朋友]",438,470+fixedOffsetY) 84 | }else if(kouKanLevel>5){ 85 | graphics.drawString("${HoshinoYumemiConfig.HoshinoYumemiNoName}对你的态度:[熟悉]",438,470+fixedOffsetY) 86 | }else if(kouKanLevel>3){ 87 | graphics.drawString("${HoshinoYumemiConfig.HoshinoYumemiNoName}对你的态度:[一般]",438,470+fixedOffsetY) 88 | }else if(kouKanLevel>1){ 89 | graphics.drawString("${HoshinoYumemiConfig.HoshinoYumemiNoName}对你的态度:[比较冷漠]",438,470+fixedOffsetY) 90 | }else if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[target.id]!! >-1){ 91 | graphics.drawString("${HoshinoYumemiConfig.HoshinoYumemiNoName}对你的态度:[冷漠]",438,470+fixedOffsetY) 92 | }else{ 93 | graphics.drawString("${HoshinoYumemiConfig.HoshinoYumemiNoName}对你的态度:[讨厌]",438,470+fixedOffsetY) 94 | } 95 | graphics.drawString((100-kouKanValue).toString(),552,500+fixedOffsetY) 96 | graphics.font = Font("楷体", Font.PLAIN ,24) 97 | val fixedY = graphics.fontMetrics.ascent - (graphics.fontMetrics.height / 2 - 24 / 2) 98 | graphics.drawString("+"+kouKanAdd.toBigDecimal().setScale(2, RoundingMode.HALF_UP).toString(),1010,315+fixedY) 99 | graphics.drawString("+"+moneyAdd.toBigDecimal().setScale(2, RoundingMode.HALF_UP).toString(),983,345+fixedY) 100 | graphics.drawString("时间:"+Date().toString(),400,540+fixedY) 101 | graphics.font = Font("楷体", Font.PLAIN ,36) 102 | val yFixed = graphics.fontMetrics.ascent - (graphics.fontMetrics.height / 2 - 36 / 2) 103 | graphics.drawString(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[target.id]!!.toBigDecimal().setScale(2, RoundingMode.HALF_UP).toString(),620,340+yFixed) 104 | graphics.dispose() 105 | val uuidFileName="Yumemi/"+target.id.toString()+".png" 106 | val outPutImage = File(uuidFileName) 107 | ImageIO.write(newImg, "png", outPutImage) 108 | return outPutImage.toExternalResource() 109 | } 110 | 111 | @OptIn(ConsoleExperimentalApi::class) 112 | @SubCommand("add","添加") 113 | @Description("增加好感度") 114 | suspend fun CommandSender.add(member : Member, Amount : Long) { 115 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!=null){ 116 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = Amount + HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!! 117 | if(HoshinoYumemiUser.HoshinoYumemiNoSpecialUser.contains(member.id)){ 118 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!! >1000.0){ 119 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = 1000.0 120 | } 121 | }else if(member.isOwner()||member.isAdministrator()){ 122 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!! >900.0){ 123 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = 900.0 124 | } 125 | }else{ 126 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!! >800.0){ 127 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = 800.0 128 | } 129 | } 130 | sendMessage(member.nick + " 的当前好感:"+HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id].toString()) 131 | }else{ 132 | sendMessage("用户不存在") 133 | } 134 | } 135 | @SubCommand("decrease","减少") 136 | @Description("减少好感度") 137 | suspend fun CommandSender.decrease(member : Member, Amount : Long) { 138 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!=null){ 139 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!! - Amount 140 | sendMessage(member.nick + " 的当前好感:"+HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id].toString()) 141 | }else{ 142 | sendMessage("用户不存在") 143 | } 144 | } 145 | @SubCommand("bladd","加入黑名单") 146 | @Description("添加黑名单") 147 | suspend fun CommandSender.bladd(Target : Long) { 148 | HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.add(Target) 149 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[Target] = -800.0 150 | } 151 | // 152 | @SubCommand("blrem","移除黑名单") 153 | @Description("移出黑名单") 154 | suspend fun CommandSender.blrem(Target : Long) { 155 | HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.remove(Target) 156 | } 157 | @SubCommand("addall","全体添加") 158 | @Description("给全体增加好感度") 159 | suspend fun CommandSender.addall(Amount : Long) { 160 | val memberSet = subject?.id?.let { bot?.getGroup(it)?.members } ?: return 161 | for(member in memberSet) { 162 | if (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] != null) { 163 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = 164 | Amount + HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!! 165 | if (HoshinoYumemiUser.HoshinoYumemiNoSpecialUser.contains(member.id)) { 166 | if (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!! > 1000.0) { 167 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = 1000.0 168 | } 169 | } else if (member.isOwner() || member.isAdministrator()) { 170 | if (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!! > 900.0) { 171 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = 900.0 172 | } 173 | } else { 174 | if (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!! > 800.0) { 175 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = 800.0 176 | } 177 | } 178 | } 179 | } 180 | sendMessage("完成") 181 | } 182 | @SubCommand("decreaseall","全体减少") 183 | @Description("给全体减少好感度") 184 | suspend fun CommandSender.decreaseall(Amount : Long) { 185 | val memberSet = subject?.id?.let { bot?.getGroup(it)?.members } ?: return 186 | for(member in memberSet) { 187 | if (HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] != null) { 188 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id] = 189 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id]!! - Amount 190 | sendMessage(member.nick + " 的当前好感:" + HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[member.id].toString()) 191 | } 192 | } 193 | sendMessage("完成") 194 | } 195 | } 196 | 197 | object HoshinoYumemiMoneyCommand : CompositeCommand( 198 | HoshiniYumemi, "Money","金钱", 199 | description = "操作金钱", 200 | ){ 201 | @SubCommand("add","添加") 202 | @Description("增加金钱") 203 | suspend fun CommandSender.add(member : Member, Amount : Long) { 204 | if(HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id]!=null){ 205 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id] = Amount + HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id]!! 206 | sendMessage(member.nick + " 的当前金钱:"+HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id].toString()) 207 | }else{ 208 | sendMessage("用户不存在") 209 | } 210 | } 211 | @SubCommand("decrease","减少") 212 | @Description("减少金钱") 213 | suspend fun CommandSender.decrease(member : Member, Amount : Long) { 214 | if(HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id]!=null){ 215 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id] = HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id]!! - Amount 216 | sendMessage(member.nick + " 的当前金钱:"+HoshinoYumemiMoney.HoshinoYumemiNoMoney[member.id].toString()) 217 | }else{ 218 | sendMessage("用户不存在") 219 | } 220 | } 221 | } 222 | 223 | object HoshinoYumemiReplyListCommand : CompositeCommand( 224 | HoshiniYumemi, "DataList","数据", 225 | description = "操作回复列表与商店列表", 226 | ){ 227 | @SubCommand("replyadd","添加回复") 228 | @Description("增加回复") 229 | suspend fun CommandSender.replyadd(input : String, KouKannLevel : Long, output : String) { 230 | if(KouKannLevel>10){ 231 | sendMessage("KouKannLevel最大为10") 232 | return 233 | }else{ 234 | if(HoshinoYumemiReplyList.HoshinoYumemiNoReplyList[input]==null){ 235 | HoshinoYumemiReplyList.HoshinoYumemiNoReplyList[input] = mutableSetOf() 236 | } 237 | HoshinoYumemiReplyList.HoshinoYumemiNoReplyList[input]?.add(mapOf(KouKannLevel to output)) 238 | sendMessage("添加成功") 239 | } 240 | } 241 | @SubCommand("replydel","删除回复") 242 | @Description("删除指定回复") 243 | suspend fun CommandSender.replydel(input : String, KouKannLevel : Long, output : String) { 244 | if(HoshinoYumemiReplyList.HoshinoYumemiNoReplyList[input]==null|| HoshinoYumemiReplyList.HoshinoYumemiNoReplyList[input]?.contains(mapOf(KouKannLevel to output)) == false){ 245 | return 246 | } 247 | HoshinoYumemiReplyList.HoshinoYumemiNoReplyList[input]?.remove(mapOf(KouKannLevel to output)) 248 | if(HoshinoYumemiReplyList.HoshinoYumemiNoReplyList[input]?.isEmpty() == true){ 249 | HoshinoYumemiReplyList.HoshinoYumemiNoReplyList.remove(input) 250 | } 251 | sendMessage("删除成功") 252 | } 253 | @SubCommand("shopadd","添加商品") 254 | @Description("添加商品") 255 | suspend fun CommandSender.shopadd(name : String, cost : Double) { 256 | HoshinoYumemiShop.HoshinoYumemiNoShop.add(mutableMapOf(name to cost)) 257 | sendMessage("商品添加成功") 258 | } 259 | @SubCommand("shopdel","删除商品") 260 | @Description("删除商品") 261 | suspend fun CommandSender.shopdel(name : String, cost : Double) { 262 | HoshinoYumemiShop.HoshinoYumemiNoShop.remove(mutableMapOf(name to cost)) 263 | sendMessage("商品删除成功") 264 | } 265 | } 266 | 267 | object HoshinoYumemiTencentCloudAPI : CompositeCommand( 268 | HoshiniYumemi, "TCAPI","腾讯云", 269 | description = "腾讯云API", 270 | ){ 271 | @SubCommand("机器翻译","mt") 272 | @Description("机器翻译(input:输入的语句,lang:目标语言:zh(简体中文):en(英语)、ja(日语)、ko(韩语)、fr(法语)、es(西班牙语)、it(意大利语)、de(德语)、tr(土耳其语)、ru(俄语)、pt(葡萄牙语)、vi(越南语)、id(印尼语)、th(泰语)、ms(马来语))") 273 | suspend fun CommandSender.MT(input : String ,lang : String) { 274 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 275 | return 276 | } 277 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(user!!.id)){ 278 | sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName+"绝对不会为你做事的") 279 | return 280 | } 281 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user?.id]!! <400.0){ 282 | sendMessage("我为什么要为你做这些?") 283 | return 284 | }else if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user?.id]!! <700.0){ 285 | if(HoshinoYumemiMoney.HoshinoYumemiNoMoney[user?.id]!! < input.length*3 ){ 286 | sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName + "酱是需要报酬才可以帮你做事的呢,但是你的金币貌似不够("+(input.length*3).toString()+")") 287 | return 288 | } 289 | sendMessage("扣除了"+(input.length*3).toString()+"金币") 290 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id] = HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]!! - (input.length*3).toDouble() 291 | } 292 | try { 293 | val cred = Credential( 294 | HoshinoYumemiTencentCloudApiConfig.HoshinoYumemiSecretId, 295 | HoshinoYumemiTencentCloudApiConfig.HoshinoYumemiSecretKey 296 | ) 297 | val httpProfile = HttpProfile() 298 | httpProfile.endpoint = "tmt.tencentcloudapi.com" 299 | val clientProfile = ClientProfile() 300 | clientProfile.httpProfile = httpProfile 301 | val client = TmtClient(cred, "ap-beijing", clientProfile) 302 | val req = TextTranslateRequest() 303 | req.sourceText = input.replace("_"," ") 304 | req.source = "auto" 305 | req.target = lang 306 | req.projectId = 0L 307 | val resp = client.TextTranslate(req) 308 | sendMessage("翻译结果:" + resp.targetText) 309 | }catch (e: TencentCloudSDKException) { 310 | if(e.toString().contains("不支持的语种")){ 311 | try{ 312 | val cred = Credential( 313 | HoshinoYumemiTencentCloudApiConfig.HoshinoYumemiSecretId, 314 | HoshinoYumemiTencentCloudApiConfig.HoshinoYumemiSecretKey 315 | ) 316 | val httpProfile = HttpProfile() 317 | httpProfile.endpoint = "tmt.tencentcloudapi.com" 318 | val clientProfile = ClientProfile() 319 | clientProfile.httpProfile = httpProfile 320 | val client = TmtClient(cred, "ap-beijing", clientProfile) 321 | val requestTmp = TextTranslateRequest() 322 | requestTmp.sourceText = input.replace("_"," ") 323 | requestTmp.source = "auto" 324 | requestTmp.target = "zh" 325 | requestTmp.projectId = 0L 326 | val respTmp = client.TextTranslate(requestTmp) 327 | requestTmp.sourceText = respTmp.targetText 328 | requestTmp.source = "zh" 329 | requestTmp.target = lang 330 | val respOut = client.TextTranslate(requestTmp) 331 | sendMessage("翻译结果:" + respOut.targetText) 332 | }catch (f: TencentCloudSDKException) { 333 | sendMessage(f.toString()) 334 | } 335 | }else{ 336 | sendMessage(e.toString()) 337 | } 338 | } 339 | } 340 | /*@SubCommand 341 | @Description("OCR") 342 | suspend fun CommandSender.OCR(input : Image) { 343 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(user!!.id)){ 344 | sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName+"绝对不会为你做事的") 345 | return 346 | } 347 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 348 | return 349 | } 350 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user?.id]!! <500.0){ 351 | sendMessage("我为什么要为你做这些?") 352 | return 353 | }else if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user?.id]!! <800.0){ 354 | if(HoshinoYumemiMoney.HoshinoYumemiNoMoney[user?.id]!! <1000.0){ 355 | sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName + "酱是需要报酬才可以帮你做事的呢,但是你的金币貌似不够(1000)") 356 | return 357 | } 358 | sendMessage("扣除了1000金币") 359 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id] = HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]!! - 1000.0 360 | } 361 | try { 362 | val cred = Credential( 363 | HoshinoYumemiTencentCloudApiConfig.HoshinoYumemiSecretId, 364 | HoshinoYumemiTencentCloudApiConfig.HoshinoYumemiSecretKey 365 | ) 366 | val httpProfile = HttpProfile() 367 | httpProfile.endpoint = "ocr.tencentcloudapi.com" 368 | val clientProfile = ClientProfile() 369 | clientProfile.httpProfile = httpProfile 370 | val client = OcrClient(cred, "", clientProfile) 371 | val req = GeneralHandwritingOCRRequest() 372 | req.imageUrl=input.queryUrl() 373 | val resp = client.GeneralHandwritingOCR(req) 374 | sendMessage("结果:"+resp.textDetections) 375 | } catch (e: TencentCloudSDKException) { 376 | sendMessage(e.toString()) 377 | } 378 | } 379 | */ 380 | } 381 | 382 | object HoshinoYumemiSeTuCommand : CompositeCommand( 383 | HoshiniYumemi, "eroImage","涩图","色图", 384 | description = "涩图", 385 | ){ 386 | 387 | @OptIn(ExperimentalSerializationApi::class) 388 | suspend fun handleLoliconApi(r18 : Boolean = false, num : Int = 1, keyword : String = "", size : String = "regular", proxy : String = "i.pixiv.re", contact:Contact, user :User) : List{ 389 | var urlStr = "https://api.lolicon.app/setu/v2?size=${size}&proxy=${proxy}&keyword=${keyword}&num=${num}" 390 | if(keyword == "rand"){ 391 | urlStr = "https://api.lolicon.app/setu/v2?size=${size}&proxy=${proxy}&num=${num}" 392 | } 393 | urlStr.replace("r18=1","").replace("r18=2","") 394 | if(urlStr.contains("r18")||urlStr.contains("R18")){ 395 | contact.sendMessage("不可以瑟瑟") 396 | return mutableListOf() 397 | } 398 | var req = OkHttpClient() 399 | val data = req.newCall(Request.Builder().url(urlStr).build()).execute() 400 | val resq : LoliconJson = Json.decodeFromString(data.body!!.string()) 401 | if(resq.data.isEmpty()){ 402 | return mutableListOf() 403 | }else{ 404 | val msgChainHandle = mutableListOf() 405 | for((i, element) in resq.data.withIndex()){ 406 | val outPutImage = withContext(Dispatchers.IO) { 407 | ImageIO.read(URL(element.urls.regular)) 408 | } 409 | val newImage = File("Yumemi/${UUID.randomUUID().toString().replace("-","")}.jpg") 410 | withContext(Dispatchers.IO) { 411 | ImageIO.write(outPutImage, "png", newImage) 412 | } 413 | msgChainHandle.add(ForwardMessage.Node(user.id, i,"LSP", buildMessageChain { 414 | +PlainText("Pixiv ID:${element.pid}\n作者:${element.author}\n标签:${element.tags}\n") 415 | +newImage.uploadAsImage(contact) 416 | })) 417 | } 418 | return msgChainHandle 419 | } 420 | } 421 | 422 | @OptIn(ExperimentalSerializationApi::class) 423 | @SubCommand("s","搜索") 424 | @Description("搜图") 425 | suspend fun CommandSender.s(image : Image) { 426 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 427 | return 428 | } 429 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(user!!.id)){ 430 | sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName+"绝对不会为你做事的") 431 | return 432 | } 433 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user?.id]!! <500.0){ 434 | sendMessage("我为什么要为你做这些?") 435 | return 436 | }else if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user?.id]!! <800.0){ 437 | if(HoshinoYumemiMoney.HoshinoYumemiNoMoney[user?.id]!! < 2000 ){ 438 | sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName + "酱是需要报酬才可以帮你做事的呢,但是你的金币貌似不够(2000)") 439 | return 440 | } 441 | sendMessage("扣除了2000金币") 442 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id] = HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]!! - 2000.0.toDouble() 443 | } 444 | try { 445 | val url = image.queryUrl() 446 | var req = OkHttpClient() 447 | val data = req.newCall( 448 | Request.Builder().url("https://saucenao.com/search.php?db=999&output_type=2&testmode=1&numres=6&url=${url}&api_key=${HoshinoYumemiSaucenaoApiConfig.HoshinoYumemiSaucenaoSecretKey}").get().build() 449 | ).execute() 450 | if(data.isSuccessful) { 451 | //sendMessage("https://saucenao.com/search.php?db=999&output_type=2&testmode=1&numres=6&url=${url}&api_key=${HoshinoYumemiSaucenaoApiConfig.HoshinoYumemiSaucenaoSecretKey}") 452 | val jsonTmp = Json{ 453 | ignoreUnknownKeys = true 454 | encodeDefaults =true 455 | coerceInputValues=true 456 | } 457 | val resq: SaucenaoJson = jsonTmp.decodeFromString(data.body!!.string()); 458 | //.decodeFromString(test.replace("\"results\":[{","\"result\":[{")) 459 | if(resq.results.isNotEmpty()){ 460 | val msgChainHandle = mutableListOf() 461 | for((i, element) in resq.results.withIndex()){ 462 | msgChainHandle.add(ForwardMessage.Node(user!!.id, i,"搜索者", buildMessageChain { 463 | +PlainText("相似度:"+element.header.similarity+"%\n") 464 | +PlainText(element.data.toJsonString().replace("\\/","/")) 465 | })) 466 | } 467 | val msg = RawForwardMessage(msgChainHandle).render( 468 | object : ForwardMessage.DisplayStrategy { 469 | override fun generateTitle(forward: RawForwardMessage) = "搜索结果" 470 | override fun generateSummary(forward: RawForwardMessage) = "搜索结果" 471 | } 472 | ) 473 | sendMessage(msg)?.recallIn(2*60*1000) 474 | } 475 | }else{ 476 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user?.id]!! <800.0){ 477 | sendMessage("返还了2000金币") 478 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id] = HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]!! + 2000.0.toDouble() 479 | } 480 | } 481 | }catch(e :Exception){ 482 | println(e.toString()) 483 | } 484 | } 485 | @OptIn(ExperimentalSerializationApi::class) 486 | @SubCommand("g","发几张") 487 | @Description("获取涩图") 488 | suspend fun CommandSender.g(tag : String,amount : Long) { 489 | if(subject==null||user==null){ 490 | return 491 | } 492 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 493 | return 494 | } 495 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(user!!.id)){ 496 | sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName+"绝对不会为你做事的") 497 | return 498 | } 499 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user?.id]!! <400.0){ 500 | sendMessage("我为什么要为你做这些?") 501 | return 502 | }else if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user?.id]!! <700.0){ 503 | if(HoshinoYumemiMoney.HoshinoYumemiNoMoney[user?.id]!! < 100 *amount){ 504 | sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName + "酱是需要报酬才可以帮你做事的呢,但是你的金币貌似不够(${100*amount})") 505 | return 506 | } 507 | if(amount>5){ 508 | sendMessage("少冲点") 509 | return 510 | } 511 | if(amount<1){ 512 | sendMessage("参数错误") 513 | return 514 | } 515 | sendMessage("扣除了${100*amount}金币") 516 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id] = HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]!! - (100.0*amount).toDouble() 517 | } 518 | if(amount>5){ 519 | sendMessage("少冲点") 520 | return 521 | } 522 | if(amount<1){ 523 | sendMessage("参数错误") 524 | return 525 | } 526 | coroutineScope { 527 | launch { 528 | try { 529 | val msg = RawForwardMessage(handleLoliconApi(false, amount.toInt(), tag, "regular", "i.pixiv.re", subject!!, user!!)).render( 530 | object : ForwardMessage.DisplayStrategy { 531 | override fun generateTitle(forward: RawForwardMessage) = "${forward.nodeList.size}张${tag}色图" 532 | override fun generateSummary(forward: RawForwardMessage) = "查看${forward.nodeList.size}张${tag}色图" 533 | } 534 | ) 535 | if(msg.nodeList.isEmpty()){ 536 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user!!.id]!!<700) { 537 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id] = HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]!! + (100.0*amount).toDouble() 538 | sendMessage("获取失败,返还了${100 * amount}金币") 539 | } 540 | }else{ 541 | sendMessage(msg)?.recallIn(30000) 542 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user!!.id]!!<700) { 543 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id] = 544 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]!! + (100.0 * (amount - msg.nodeList.size.toLong())).toDouble() 545 | } 546 | } 547 | } catch (e: Exception) { 548 | println(e.toString()) 549 | } 550 | } 551 | } 552 | } 553 | } 554 | 555 | object HoshinoYumemiWorkCommand : CompositeCommand( 556 | HoshiniYumemi, "AdmCmd","上帝指令", 557 | description = "管理员指令", 558 | ){ 559 | @SubCommand("Disable","NLP") 560 | @Description("禁用NLP的群聊") 561 | suspend fun CommandSender.Disable(Mode : String ,GroupId : Long) { 562 | if(bot==null){ 563 | return 564 | } 565 | if(Mode=="add"){ 566 | if(GroupId==0L){ 567 | for(group in bot!!.groups){ 568 | HoshinoYumemiTencentCloudDisabledGroups.HoshinoYumemiNoTencentCloudDisabledGroups.add(group.id) 569 | sendMessage("已在全部群中禁用") 570 | } 571 | }else{ 572 | if(bot!!.getGroup(GroupId)!=null){ 573 | if(HoshinoYumemiTencentCloudDisabledGroups.HoshinoYumemiNoTencentCloudDisabledGroups.add(GroupId)){ 574 | sendMessage("添加成功") 575 | }else{ 576 | sendMessage("添加失败") 577 | } 578 | } 579 | } 580 | return 581 | } 582 | if(Mode=="del"){ 583 | if(GroupId==0L){ 584 | HoshinoYumemiTencentCloudDisabledGroups.HoshinoYumemiNoTencentCloudDisabledGroups.clear() 585 | sendMessage("已在所有群中启用") 586 | }else{ 587 | if(HoshinoYumemiTencentCloudDisabledGroups.HoshinoYumemiNoTencentCloudDisabledGroups.remove(GroupId)){ 588 | sendMessage("删除成功") 589 | }else{ 590 | sendMessage("删除失败") 591 | } 592 | } 593 | return 594 | } 595 | sendMessage("参数错误") 596 | } 597 | @OptIn(ExperimentalSerializationApi::class) 598 | @SubCommand("添加工作","addWork") 599 | @Description("添加工作") 600 | suspend fun CommandSender.addWork(requiredSpecialize : String,reward : Double) { 601 | if(HoshinoYumemiCourse.HoshinoYumemiNoCourses[requiredSpecialize]==null){ 602 | sendMessage("不存在当前专业") 603 | return 604 | } 605 | if(userJobs.job.find{it.requiredSpecialized==requiredSpecialize}!=null){ 606 | userJobs.job.find{it.requiredSpecialized==requiredSpecialize}!!.reward=reward 607 | sendMessage("已存在该工作,修改了reward") 608 | } 609 | if(userJobs.job.add(BotJobs.JobsBot(requiredSpecialize, reward))){ 610 | sendMessage("添加成功") 611 | val jobsDataFile = File("data/srh.shirakana.hoshinoyumemi.plugin/Jobs.json") 612 | val userJobsJson = Json.encodeToString(userJobs) 613 | val jsonObjectUserJobs: JSONObject = JSONObject.parseObject(userJobsJson) 614 | val formatStrUserJobs: String = JSON.toJSONString( 615 | jsonObjectUserJobs, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, 616 | SerializerFeature.WriteDateUseDateFormat 617 | ) 618 | jobsDataFile.writeText(formatStrUserJobs) 619 | }else{ 620 | sendMessage("添加失败") 621 | } 622 | } 623 | @OptIn(ExperimentalSerializationApi::class) 624 | @SubCommand("删除工作","delWork") 625 | @Description("删除工作") 626 | suspend fun CommandSender.delWork(requiredSpecialize : String) { 627 | if(userJobs.job.remove(userJobs.job.find{it.requiredSpecialized == requiredSpecialize})){ 628 | sendMessage("删除成功") 629 | val jobsDataFile = File("data/srh.shirakana.hoshinoyumemi.plugin/Jobs.json") 630 | val userJobsJson = Json.encodeToString(userJobs) 631 | val jsonObjectUserJobs: JSONObject = JSONObject.parseObject(userJobsJson) 632 | val formatStrUserJobs: String = JSON.toJSONString( 633 | jsonObjectUserJobs, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, 634 | SerializerFeature.WriteDateUseDateFormat 635 | ) 636 | jobsDataFile.writeText(formatStrUserJobs) 637 | }else{ 638 | sendMessage("删除失败") 639 | } 640 | } 641 | @OptIn(ExperimentalSerializationApi::class) 642 | @SubCommand("添加考试题目","addTest") 643 | @Description("添加考试题目") 644 | suspend fun CommandSender.addTest(Specialize : String,Question : String,Answer : String) { 645 | if(HoshinoYumemiCourse.HoshinoYumemiNoCourses[Specialize]==null){ 646 | HoshinoYumemiCourse.HoshinoYumemiNoCourses[Specialize]= mutableSetOf() 647 | } 648 | if(HoshinoYumemiCourse.HoshinoYumemiNoCourses[Specialize]!!.find{it.keys.contains(Question)}!=null){ 649 | sendMessage("该题目已经存在") 650 | return 651 | } 652 | if(HoshinoYumemiCourse.HoshinoYumemiNoCourses[Specialize]!!.add(mapOf(Question to Answer))){ 653 | sendMessage("添加成功") 654 | }else{ 655 | sendMessage("添加失败") 656 | } 657 | if(HoshinoYumemiCourse.HoshinoYumemiNoCourses[Specialize]!!.isEmpty()){ 658 | HoshinoYumemiCourse.HoshinoYumemiNoCourses.remove(Specialize) 659 | } 660 | } 661 | @OptIn(ExperimentalSerializationApi::class) 662 | @SubCommand("删除考试题目","delTest") 663 | @Description("删除考试题目") 664 | suspend fun CommandSender.delTest(Specialize : String,Question : String) { 665 | if(HoshinoYumemiCourse.HoshinoYumemiNoCourses[Specialize]==null){ 666 | sendMessage("不存在此专业") 667 | return 668 | } 669 | if(HoshinoYumemiCourse.HoshinoYumemiNoCourses[Specialize]?. 670 | remove(HoshinoYumemiCourse.HoshinoYumemiNoCourses[Specialize]?.find{it.keys.elementAt(0)==Question}) 671 | ==true){ 672 | sendMessage("删除成功") 673 | }else{ 674 | sendMessage("删除失败") 675 | } 676 | if(HoshinoYumemiCourse.HoshinoYumemiNoCourses[Specialize]!!.isEmpty()){ 677 | HoshinoYumemiCourse.HoshinoYumemiNoCourses.remove(Specialize) 678 | } 679 | } 680 | } 681 | 682 | object HoshinoYumemiUserCommand : CompositeCommand( 683 | HoshiniYumemi, "usrcmd","我的", 684 | description = "用户指令", 685 | ){ 686 | @SubCommand("查看好感","kk") 687 | @Description("查看好感") 688 | suspend fun CommandSender.kk() { 689 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 690 | return 691 | } 692 | if(user==null)return; 693 | val msgChain = buildMessageChain { 694 | +At(user!!) 695 | +PlainText("您当前的好感度是:"+HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user!!.id]!!.toBigDecimal().setScale(2, RoundingMode.HALF_UP).toString()) 696 | } 697 | sendMessage(msgChain) 698 | } 699 | @SubCommand("查看金钱","mon") 700 | @Description("查看金钱") 701 | suspend fun CommandSender.mon() { 702 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 703 | return 704 | } 705 | if(user==null)return; 706 | val msgChain = buildMessageChain { 707 | +At(user!!) 708 | +PlainText("您当前拥有的金币数量是:"+HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]!!.toBigDecimal().setScale(2, RoundingMode.HALF_UP).toString()) 709 | } 710 | sendMessage(msgChain) 711 | } 712 | @SubCommand("查看礼物","giftlist") 713 | @Description("查看存在的礼物") 714 | suspend fun CommandSender.giftlist() { 715 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 716 | return 717 | } 718 | if(HoshinoYumemiShop.HoshinoYumemiNoShop.isEmpty()){ 719 | sendMessage("商店中无任何礼物") 720 | return 721 | } 722 | var msg = "" 723 | for((index, good) in HoshinoYumemiShop.HoshinoYumemiNoShop.withIndex()){ 724 | msg+="[ID:$index]:\n" 725 | for((key,value) in good){ 726 | msg+="名称:[$key] 价格:[$value]" 727 | } 728 | msg+="\n" 729 | } 730 | sendMessage(msg) 731 | } 732 | @SubCommand("送礼物","gift") 733 | @Description("给BOT送礼物") 734 | suspend fun CommandSender.gift(ID : Long) { 735 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 736 | return 737 | } 738 | if(user==null)return; 739 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(user!!.id)){ 740 | sendMessage(HoshinoYumemiConfig.HoshinoYumemiNoName+"不接受你的礼物!") 741 | return 742 | } 743 | if(ID < HoshinoYumemiShop.HoshinoYumemiNoShop.size){ 744 | val good = HoshinoYumemiShop.HoshinoYumemiNoShop.elementAt(ID.toInt()) 745 | var cost=0.0 746 | var name="" 747 | for((key,value)in good){ 748 | cost=value 749 | name=key 750 | } 751 | if(HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]!!>cost){ 752 | HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]= HoshinoYumemiMoney.HoshinoYumemiNoMoney[user!!.id]!!-cost 753 | val msgChain = buildMessageChain { 754 | +PlainText("感谢") 755 | +At(user!!) 756 | +PlainText("送我$name") 757 | } 758 | HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user!!.id] = HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user!!.id]!! + (cost/1000.0).toDouble() 759 | sendMessage(msgChain) 760 | }else{ 761 | sendMessage("金币不足") 762 | } 763 | }else{ 764 | sendMessage("不存在该ID") 765 | } 766 | } 767 | @SubCommand("参加考试","jointest") 768 | @Description("参加指定专业的考试") 769 | suspend fun CommandSender.jointest(name : String) { 770 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user!!.id]!! <0){ 771 | subject!!.sendMessage("哼,不理你了") 772 | return 773 | } 774 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 775 | return 776 | } 777 | if(user==null)return; 778 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(user!!.id)){ 779 | return 780 | } 781 | if(userS[user!!.id]?.testState==true){ 782 | sendMessage("请勿重复参加考试") 783 | return 784 | } 785 | if(!HoshinoYumemiCourse.HoshinoYumemiNoCourses.keys.contains(name)){ 786 | sendMessage("没有指定的专业") 787 | return 788 | } 789 | if(userS[user!!.id]?.specialized!="null"&&userS[user!!.id]?.specialized!=name){ 790 | sendMessage("若参加其他专业考试,不会增长您的等级") 791 | } 792 | userS[user!!.id]?.testSpecialize=name 793 | if(userS[user!!.id]?.specialized=="null"){ 794 | userS[user!!.id]?.specialized=name 795 | } 796 | if(HoshinoYumemiCourse.HoshinoYumemiNoCourses[name]!!.isEmpty())return 797 | val testQuestIndex = HoshinoYumemiCourse.HoshinoYumemiNoCourses[name]!!.size-1 798 | userS[user!!.id]?.testQuest= 799 | HoshinoYumemiCourse.HoshinoYumemiNoCourses[name]!!.elementAt((0..testQuestIndex).random()).keys.elementAt(0) 800 | userS[user!!.id]?.testState=true 801 | sendMessage(buildMessageChain { 802 | +At(user!!) 803 | +PlainText("题库中共有${testQuestIndex+1}道题\n题目:\n${ userS[user!!.id]?.testQuest!!.replace("<_>"," ").replace("","\t").replace("","\n") }\n请回答(需要ATBOT并输入答案)") 804 | }) 805 | } 806 | @SubCommand("退出考试","exittest") 807 | @Description("退出考试") 808 | suspend fun CommandSender.exittest() { 809 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user!!.id]!! <0){ 810 | subject!!.sendMessage("哼,不理你了") 811 | return 812 | } 813 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 814 | return 815 | } 816 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(user!!.id)){ 817 | return 818 | } 819 | if(user==null)return; 820 | if(userS[user!!.id]?.testState==true){ 821 | userS[user!!.id]?.testState=false 822 | userS[user!!.id]?.testSpecialize="" 823 | userS[user!!.id]?.testQuest="" 824 | sendMessage("退出成功") 825 | return 826 | } 827 | } 828 | @SubCommand("有什么专业","LS") 829 | @Description("列出目前存在的专业") 830 | suspend fun CommandSender.LS() { 831 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user!!.id]!! <0){ 832 | subject!!.sendMessage("哼,不理你了") 833 | return 834 | } 835 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 836 | return 837 | } 838 | if(user==null)return; 839 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(user!!.id)){ 840 | return 841 | } 842 | sendMessage("目前有的专业:${HoshinoYumemiCourse.HoshinoYumemiNoCourses.keys.toString()}") 843 | } 844 | @SubCommand("我的专业","mysp") 845 | @Description("显示自己的专业及学位") 846 | suspend fun CommandSender.mysp() { 847 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user!!.id]!! <0){ 848 | subject!!.sendMessage("哼,不理你了") 849 | return 850 | } 851 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 852 | return 853 | } 854 | if(user==null)return; 855 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(user!!.id)){ 856 | return 857 | } 858 | sendMessage("目前有的专业:${userS[user!!.id]!!.specialized}\n目前的学位:${userS[user!!.id]!!.degree}") 859 | } 860 | @SubCommand("放弃学位","giveupmysp") 861 | @Description("放弃当前学位") 862 | suspend fun CommandSender.giveupmysp() { 863 | if(HoshinoYumemiKouKann.HoshinoYumemiNoKouKann[user!!.id]!! <0){ 864 | subject!!.sendMessage("哼,不理你了") 865 | return 866 | } 867 | if(!HoshinoYumemiSwitch.HoshinoYumemiNoSwitch){ 868 | return 869 | } 870 | if(user==null)return; 871 | if(HoshinoYumemiBlackList.HoshinoYumemiNoBlackList.contains(user!!.id)){ 872 | return 873 | } 874 | userS[user!!.id]!!.specialized="null" 875 | userS[user!!.id]!!.degree=0 876 | sendMessage("放弃成功") 877 | } 878 | } 879 | -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/command/LoliconJson.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.command 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | import kotlinx.serialization.Serializable 5 | import kotlinx.serialization.encodeToString 6 | import kotlinx.serialization.json.Json 7 | 8 | @Serializable 9 | data class LoliconJson(val error: String, val data: List) { 10 | @Serializable 11 | data class Data( 12 | val pid: Int, 13 | val p: Int, 14 | val uid: Int, 15 | val title: String, 16 | val author: String, 17 | val r18: Boolean, 18 | val width: Int, 19 | val height: Int, 20 | val tags: List, 21 | val ext: String, 22 | val uploadDate: Long, 23 | val urls: Urls 24 | ) { 25 | @Serializable 26 | data class Urls(val regular: String) 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/command/SaucenaoJson.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.command 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | import kotlinx.serialization.Serializable 5 | import kotlinx.serialization.encodeToString 6 | import kotlinx.serialization.json.Json 7 | 8 | @Serializable 9 | data class SaucenaoJson(val header : Header,val results : List){ 10 | @Serializable 11 | data class Header( 12 | val user_id: String, 13 | val account_type: String, 14 | val short_limit: String, 15 | val long_limit: String, 16 | val long_remaining: Int, 17 | val short_remaining: Int, 18 | val status: Int, 19 | val results_requested: Int, 20 | val index : Map, 21 | val search_depth: String, 22 | val minimum_similarity: Double, 23 | val query_image_display: String, 24 | val query_image: String, 25 | val results_returned: Int 26 | ){ 27 | @Serializable 28 | data class INDEX( 29 | val status :Int, 30 | val parent_id :Int, 31 | val id :Int, 32 | val results :Int 33 | ) 34 | } 35 | @Serializable 36 | data class Results( 37 | val header: HEADER, 38 | val data: DATA 39 | ){ 40 | @Serializable 41 | data class HEADER( 42 | val similarity :String, 43 | val thumbnail :String, 44 | val index_id :Int, 45 | val index_name :String, 46 | val dupes :Int, 47 | val hidden :Int 48 | ) 49 | @Serializable 50 | data class DATA( 51 | val ext_urls:List? = null, 52 | val path: String? = null, 53 | val creator_name:String? = null, 54 | val author_name:String? = null, 55 | val title:String? = null, 56 | val da_id:String? = null, 57 | val source:String? = null, 58 | val pixiv_id:Long? = null, 59 | val member_name:String? = null, 60 | val member_id:Long? = null, 61 | val anidb_aid:Long? = null, 62 | val mal_id:Long? = null, 63 | val anilist_id:Long? = null, 64 | val part:String? = null, 65 | val year:String? = null, 66 | val est_time:String? = null, 67 | val fa_id:Long? = null, 68 | val created_at:String? = null, 69 | val tweet_id:String? = null, 70 | val twitter_user_id:String? = null, 71 | val twitter_user_handle:String? = null, 72 | val eng_name:String? = null, 73 | val jp_name:String? = null, 74 | val bcy_type:String? = null, 75 | val bcy_id:Long? = null, 76 | val member_link_id:Long? = null, 77 | val fn_type:String? = null, 78 | val pawoo_id:Long? = null, 79 | val pawoo_user_acct:String? = null, 80 | val pawoo_user_username:String? = null, 81 | val type:String? = null, 82 | val mu_id:Long? = null, 83 | val pawoo_user_display_name:String? = null, 84 | val published:String? = null, 85 | val service:String? = null, 86 | val service_name:String? = null, 87 | val id:String? = null, 88 | val user_id:String? = null, 89 | val user_name:String? = null, 90 | val md_id:String? = null, 91 | val artist:String? = null, 92 | val author:String? = null, 93 | val author_url:String? = null 94 | ){ 95 | @OptIn(ExperimentalSerializationApi::class) 96 | public fun toJsonString():String{ 97 | return Json.encodeToString(this).replace("{","").replace("}","") 98 | .replace(",\"","\n\"") 99 | } 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/BaseConfig.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.ReadOnlyPluginConfig 4 | import net.mamoe.mirai.console.data.ValueDescription 5 | import net.mamoe.mirai.console.data.ValueName 6 | import net.mamoe.mirai.console.data.value 7 | 8 | object HoshinoYumemiConfig : ReadOnlyPluginConfig("HoshinoYumemiConfig") { 9 | @ValueName("Name") 10 | @ValueDescription("机器人的名字") 11 | val HoshinoYumemiNoName: String by value("梦美") 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/BlackList.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.AutoSavePluginData 4 | import net.mamoe.mirai.console.data.ValueDescription 5 | import net.mamoe.mirai.console.data.ValueName 6 | import net.mamoe.mirai.console.data.value 7 | import srh.shirakana.hoshinoyumemi.file.HoshinoYumemiKouKann.provideDelegate 8 | 9 | public object HoshinoYumemiBlackList : AutoSavePluginData("HoshinoYumemiBlackList") { 10 | 11 | @ValueName("BlackList") 12 | @ValueDescription("黑名单") 13 | val HoshinoYumemiNoBlackList: MutableSet by value() 14 | 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/Config.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.* 4 | 5 | object HoshinoYumemiTencentCloudApiConfig : ReadOnlyPluginConfig("HoshinoYumemi_TencentCloudApiConfig") { 6 | @ValueName("SecretId") 7 | @ValueDescription("腾讯云SecretId") 8 | val HoshinoYumemiSecretId: String by value("SecretId") 9 | @ValueName("SecretKey") 10 | @ValueDescription("腾讯云SecretKey") 11 | val HoshinoYumemiSecretKey: String by value("SecretKey") 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/Course.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.AutoSavePluginData 4 | import net.mamoe.mirai.console.data.ValueDescription 5 | import net.mamoe.mirai.console.data.ValueName 6 | import net.mamoe.mirai.console.data.value 7 | import srh.shirakana.hoshinoyumemi.file.HoshinoYumemiBlackList.provideDelegate 8 | 9 | public object HoshinoYumemiCourse : AutoSavePluginData("HoshinoYumemiCourse") { 10 | 11 | @ValueName("Course") 12 | @ValueDescription("题目") 13 | val HoshinoYumemiNoCourses: MutableMap>> by value() 14 | 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/Flags.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.AutoSavePluginData 4 | import net.mamoe.mirai.console.data.ValueDescription 5 | import net.mamoe.mirai.console.data.ValueName 6 | import net.mamoe.mirai.console.data.value 7 | import srh.shirakana.hoshinoyumemi.file.HoshinoYumemiReplyList.provideDelegate 8 | 9 | public object HoshinoYumemiSwitch : AutoSavePluginData("HoshinoYumemiSwitch") { 10 | 11 | @ValueName("Switch") 12 | @ValueDescription("开关") 13 | var HoshinoYumemiNoSwitch: Boolean by value(false) 14 | 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/KouKann.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.* 4 | 5 | public object HoshinoYumemiKouKann : AutoSavePluginData("HoshinoYumemiKouKann") { 6 | 7 | @ValueName("KouKannList") 8 | @ValueDescription("好感度列表") 9 | val HoshinoYumemiNoKouKann: MutableMap by value() 10 | 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/NlpDisabledGroups.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.AutoSavePluginData 4 | import net.mamoe.mirai.console.data.ValueDescription 5 | import net.mamoe.mirai.console.data.ValueName 6 | import net.mamoe.mirai.console.data.value 7 | import srh.shirakana.hoshinoyumemi.file.HoshinoYumemiKouKann.provideDelegate 8 | 9 | public object HoshinoYumemiTencentCloudDisabledGroups : AutoSavePluginData("HoshinoYumemiTencentCloudDisabledGroups") { 10 | 11 | @ValueName("HoshinoYumemiTencentCloudDisabledGroups") 12 | @ValueDescription("关闭腾讯云NLP的群聊") 13 | val HoshinoYumemiNoTencentCloudDisabledGroups: MutableSet by value() 14 | 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/Saucenao.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.ReadOnlyPluginConfig 4 | import net.mamoe.mirai.console.data.ValueDescription 5 | import net.mamoe.mirai.console.data.ValueName 6 | import net.mamoe.mirai.console.data.value 7 | 8 | object HoshinoYumemiSaucenaoApiConfig : ReadOnlyPluginConfig("HoshinoYumemiSaucenaoApiConfig") { 9 | @ValueName("SecretKey") 10 | @ValueDescription("SaucenaoSecretKey") 11 | val HoshinoYumemiSaucenaoSecretKey: String by value("SecretKey") 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/Shop.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.AutoSavePluginData 4 | import net.mamoe.mirai.console.data.ValueDescription 5 | import net.mamoe.mirai.console.data.ValueName 6 | import net.mamoe.mirai.console.data.value 7 | 8 | public object HoshinoYumemiShop : AutoSavePluginData("HoshinoYumemiShop") { 9 | 10 | @ValueName("Shop") 11 | @ValueDescription("商店列表") 12 | val HoshinoYumemiNoShop: MutableSet> by value() 13 | 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/User.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.* 4 | 5 | public object HoshinoYumemiUser : AutoSavePluginData("HoshinoYumemiUser") { 6 | 7 | @ValueName("UserStatus") 8 | @ValueDescription("用户状态") 9 | val HoshinoYumemiNoUser: MutableMap by value() 10 | 11 | @ValueName("SpecialUser") 12 | @ValueDescription("特殊用户列表") 13 | val HoshinoYumemiNoSpecialUser: MutableSet by value(mutableSetOf(1751842477)) 14 | 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/daixuexi.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.AutoSavePluginData 4 | import net.mamoe.mirai.console.data.ValueDescription 5 | import net.mamoe.mirai.console.data.ValueName 6 | import net.mamoe.mirai.console.data.value 7 | 8 | public object HoshinoYumemiDaiXueXi : AutoSavePluginData("HoshinoYumemiDaiXueXi") { 9 | 10 | @ValueName("HoshinoYumemiDaiXueXi") 11 | @ValueDescription("带学习") 12 | val HoshinoYumemiNoDaiXueXi: MutableSet by value() 13 | 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/eco.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.AutoSavePluginData 4 | import net.mamoe.mirai.console.data.ValueDescription 5 | import net.mamoe.mirai.console.data.ValueName 6 | import net.mamoe.mirai.console.data.value 7 | import srh.shirakana.hoshinoyumemi.file.HoshinoYumemiReplyList.provideDelegate 8 | 9 | public object HoshinoYumemiMoney : AutoSavePluginData("HoshinoYumemiMoney") { 10 | 11 | @ValueName("Money") 12 | @ValueDescription("金钱列表") 13 | val HoshinoYumemiNoMoney: MutableMap by value() 14 | 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/main/kotlin/srh/shirakana/hoshinoyumemi/file/replyList.kt: -------------------------------------------------------------------------------- 1 | package srh.shirakana.hoshinoyumemi.file 2 | 3 | import net.mamoe.mirai.console.data.* 4 | 5 | public object HoshinoYumemiReplyList : AutoSavePluginData("HoshinoYumemiReplyList") { 6 | 7 | //Map<发送的信息,Map<好感度,Set<回复的信息>>> 8 | @ValueName("ReplyList") 9 | @ValueDescription("回复列表") 10 | val HoshinoYumemiNoReplyList: MutableMap>> by value() 11 | 12 | } -------------------------------------------------------------------------------- /src/main/resources/Bg1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PriesiaMioShirakana/HoshinoYumemi/f3584404813ae5c2ae44c29d17e399de93a4458a/src/main/resources/Bg1.png -------------------------------------------------------------------------------- /src/main/resources/Bg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PriesiaMioShirakana/HoshinoYumemi/f3584404813ae5c2ae44c29d17e399de93a4458a/src/main/resources/Bg2.png -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin: -------------------------------------------------------------------------------- 1 | srh.shirakana.hoshinoyumemi.HoshiniYumemi -------------------------------------------------------------------------------- /src/main/resources/bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PriesiaMioShirakana/HoshinoYumemi/f3584404813ae5c2ae44c29d17e399de93a4458a/src/main/resources/bar.png -------------------------------------------------------------------------------- /src/main/resources/bar_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PriesiaMioShirakana/HoshinoYumemi/f3584404813ae5c2ae44c29d17e399de93a4458a/src/main/resources/bar_white.png --------------------------------------------------------------------------------