Compare commits
133 commits
v3.0.0-alp
...
bk-origina
Author | SHA1 | Date | |
---|---|---|---|
f1ae5730d4 | |||
051a2b2f27 | |||
a6d6ed198c | |||
0cc74be280 | |||
16131b2184 | |||
ea16395c15 | |||
e2a8217e37 | |||
dc4fad6506 | |||
63342f85b7 | |||
3f1ef6d889 | |||
69909de327 | |||
0b31a366cb | |||
7ed4d1ee84 | |||
0f9b6f4cdb | |||
1afb5583b4 | |||
bb8bb88489 | |||
3e05e6b89d | |||
d6a93ffef9 | |||
c9594fe248 | |||
ccf9600cf1 | |||
792c9e6a97 | |||
497e8a1946 | |||
03af6e4917 | |||
c908d903a9 | |||
79589edc44 | |||
a085756c7d | |||
fff76b9cc2 | |||
e1eed2164e | |||
657ae684ff | |||
4d536c5a24 | |||
6aa61cf724 | |||
64df0af9a0 | |||
73ac8983d1 | |||
a97c047566 | |||
92867a6217 | |||
1193bd0bb4 | |||
8662ee448a | |||
f3c4c6abdd | |||
a8e3b67d92 | |||
9bbe885025 | |||
2723483b7b | |||
aaf7a44d95 | |||
c5fbd67510 | |||
88cca61fe2 | |||
8ec8dd7074 | |||
b6d906228e | |||
6b7bfa5ac6 | |||
68fa7a871f | |||
604a901399 | |||
88461b45d3 | |||
e088c1fec1 | |||
c2313ee650 | |||
8b7545ac16 | |||
c1c7907e49 | |||
b3f5e4f633 | |||
1034518f5f | |||
11d89993b2 | |||
3a5e4490ee | |||
7f9d942754 | |||
50ae8ab300 | |||
40037e3798 | |||
c66f98c306 | |||
bc483e9223 | |||
bba4e8337f | |||
fd9a0ef0cb | |||
50db974497 | |||
92b83b4ca2 | |||
43527d9e6e | |||
754f981390 | |||
754aa4a923 | |||
1f8a05f189 | |||
0da0967d8a | |||
501b4d2d2c | |||
1d40be05a8 | |||
ef47598b78 | |||
a4a9fcf0b4 | |||
c5ead7d843 | |||
f62f6b8684 | |||
7cc6f86090 | |||
cd3bc05a4c | |||
eb13622c8a | |||
94085378a3 | |||
dea7909e4c | |||
b88b2c8e3d | |||
c39c65a2cc | |||
71927e060a | |||
10645c1cad | |||
af509b8455 | |||
cad2bfc2ba | |||
5de0f84cb9 | |||
671a0c958f | |||
296431bc37 | |||
5364fbd7e2 | |||
c3a6f3fcc3 | |||
c0d010acf1 | |||
e84b975266 | |||
64a87a59d8 | |||
3be587d815 | |||
72260f23ad | |||
3a42970408 | |||
e20d59f54d | |||
91bf5cc891 | |||
e570702901 | |||
fea9e1946f | |||
9ff2a7b549 | |||
3d0764e498 | |||
69881013c7 | |||
275aca9d05 | |||
1d09eab935 | |||
3c83eedd09 | |||
7b388fb293 | |||
2b4306f099 | |||
682dcb00d7 | |||
fc4e2d2ccc | |||
e14b30f8d0 | |||
c61773fb73 | |||
dba4bb2056 | |||
ec0596dcda | |||
fee16ad7d9 | |||
6dc272a78c | |||
84c7ad673c | |||
eda0259a97 | |||
774500eba0 | |||
e9f6042069 | |||
b790b805d7 | |||
d0a6d01e5b | |||
d62df2b511 | |||
4026ef2664 | |||
be0982431b | |||
50229d8c10 | |||
422b67597f | |||
6264013c6b | |||
2ee26eedc2 |
117 changed files with 3833 additions and 4082 deletions
.gitignoreLICENSEREADME.mdbuild.gradlecodestyle.xmlinspections.xml
src/main/java/land/chipmunk/chipmunkmod
ChipmunkMod.javaConfiguration.java
command
commands
AutoSkinCommand.javaClearAntiChatSpamQueueCommand.javaCloopCommand.javaCoreCommand.javaCustomChatCommand.javaDebugCommand.javaEvalCommand.javaItemCommand.javaKickCommand.javaMusicCommand.javaRainbowNameCommand.javaReloadConfigCommand.javaSayCommand.javaSelfCareCommand.javaTestCommand.javaUsernameCommand.javaValidateCommand.java
config
data
listeners
mixin
ChatHudMixin.javaChatInputSuggestorMixin.javaChatScreenMixin.javaClientCommonNetworkHandlerAccessor.javaClientConnectionAccessor.javaClientConnectionInvoker.javaClientConnectionMixin.javaClientPlayNetworkHandlerAccessor.javaClientPlayNetworkHandlerMixin.javaClientPlayerEntityMixin.javaCommandDispatcherMixin.javaElderGuardianAppearanceParticleMixin.javaFontStorageMixin.javaIdentifierMixin.javaKeyboardMixin.javaMinecraftClientAccessor.javaPlayerEntityMixin.javaPlayerListEntryAccessor.javaSoundSystemMixin.javaStringHelperMixin.javaTextFieldWidgetMixin.javaTextMixin.javaTextSerializerMixin.javaTitleScreenMixin.javaWorldRendererMixin.java
modules
Chat.javaChomeNSAuth.javaChomeNSBotCommandSuggestions.javaCommandCore.javaCommandLoopManager.javaCustomChat.javaKaboomCheck.javaRainbowName.javaSelfCare.javaSongPlayer.javaTabComplete.javaTransactionManager.java
custom_chat
song
Instrument.javaMidiConverter.javaNBSConverter.javaNote.javaSong.javaSongLoaderException.javaSongLoaderThread.java
util
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -38,4 +38,3 @@ hs_err_*.log
|
|||
replay_*.log
|
||||
*.hprof
|
||||
*.jfr
|
||||
/buildAndSend.sh
|
||||
|
|
120
LICENSE
120
LICENSE
|
@ -1,121 +1,11 @@
|
|||
Creative Commons Legal Code
|
||||
MIT License
|
||||
|
||||
CC0 1.0 Universal
|
||||
Copyright (c) 2024-2025 7cc5c4f330d47060
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
Statement of Purpose
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
||||
|
|
35
README.md
35
README.md
|
@ -3,23 +3,42 @@ My fork of [Blackilykat's fork of ChipmunkMod](https://code.chipmunk.land/Blacki
|
|||
|
||||
# Installation
|
||||
|
||||
Download the latest release from the Releases tab, make sure you have the Fabric loader and Fabric API installed for version 1.21.1, then copy the JAR file to your mods folder. Alternatively, you may follow the instructions below to get the latest code.
|
||||
Download the JAR file (not the source code archive unless you want to build it) of the latest release from the Releases tab, ensure you have the Fabric loader and Fabric API installed for version 1.21.4, then copy the JAR file to your mods folder. Alternatively, you may follow the instructions below to get the latest code.
|
||||
|
||||
# Building
|
||||
|
||||
Download the code by clicking the 3 dots icon on the right of the screen below the repository info then `Download ZIP` or `Download TAR.GZ`, then extract it.
|
||||
|
||||
Alternatively, you can download using the Git client:
|
||||
`git clone https://code.chipmunk.land/7cc5c4f330d47060/chipmunkmod.git`
|
||||
Alternatively, you can download using the [Git client](https://git-scm.com/): `git clone https://code.chipmunk.land/7cc5c4f330d47060/chipmunkmod.git`
|
||||
|
||||
Make sure you have a Java 21 JDK installed (this may not work for newer JDK versions), then go to the ChipmunkMod directory and run `./gradlew build` for Unix(-like) OSes or `gradlew.bat build` for Windows. If the build was successful, the compiled JAR file should be in `build/libs`.
|
||||
Ensure you have a Java 21 JDK installed (this may not work for other JDK versions), then go to the ChipmunkMod directory and run `./gradlew build` for Unix(-like) OSes or `gradlew.bat build` for Windows. If the build was successful, the compiled JAR file should be in `build/libs`.
|
||||
|
||||
Make sure you have the Fabric loader and Fabric API installed for version 1.21.4 (the main branch is on a newer game version than the release), and copy the JAR file to your mods folder.
|
||||
Ensure you have the Fabric loader and Fabric API installed for version 1.21.4, and copy the JAR file to your mods folder.
|
||||
|
||||
If that's not clear enough, search how to install a Fabric mod on a search engine.
|
||||
|
||||
If errors appear that you don't understand, [create an issue](https://code.chipmunk.land/7cc5c4f330d47060/chipmunkmod/issues/new) about it.
|
||||
|
||||
# Extra information
|
||||
|
||||
The mod icon used (https://commons.wikimedia.org/wiki/File:Streifenhoernchen.jpg) is in the public domain.
|
||||
# License
|
||||
|
||||
The mod icon used (https://commons.wikimedia.org/wiki/File:Streifenhoernchen.jpg) is in the public domain.
|
||||
|
||||
This project is licensed under the MIT License. Using, modifying, and distributing this software, whether in source or binary form, is allowed, even for commercial purposes. If you make any copies of this software, you MUST link back to this repository. See the LICENSE document for the full terms and conditions.
|
||||
|
||||
This software contains code from the following projects. See their commit histories for attribution.
|
||||
Fabric Example Mod (https://github.com/FabricMC/fabric-example-mod)
|
||||
Original ChipmunkMod (https://code.chipmunk.land/chipmunkmc/chipmunkmod)
|
||||
ChomeNS' fork of ChipmunkMod (https://code.chipmunk.land/ChomeNS/chipmunkmod)
|
||||
Blackilykat's fork of ChipmunkMod (https://code.chipmunk.land/Blackilykat/chipmunkmod)
|
||||
|
||||
|
||||
<!--# Development
|
||||
When commiting your changes, please use my code style.
|
||||
|
||||
In IntelliJ IDEA:
|
||||
|
||||
`Ctrl + Alt + S`, search `Code Style`, go to `Java`, click gear icon, `Import Scheme -> IntelliJ IDEA code style XML`,
|
||||
use the `codestyle.xml` file in this repository
|
||||
|
||||
`Ctrl + Alt + Shift + H`, click `Configure Inspections...`, click gear icon, `Import Profile...`,
|
||||
use the `inspections.xml` file in this repository -->
|
19
build.gradle
19
build.gradle
|
@ -1,15 +1,11 @@
|
|||
plugins {
|
||||
id 'fabric-loom' version '1.9-SNAPSHOT'
|
||||
id 'fabric-loom' version '1.10-SNAPSHOT'
|
||||
}
|
||||
|
||||
base.archivesName = project.archives_base_name
|
||||
version = project.mod_version
|
||||
group = project.maven_group
|
||||
|
||||
loom {
|
||||
accessWidenerPath = file("src/main/resources/chipmunkmod.accesswidener")
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
@ -20,14 +16,21 @@ dependencies {
|
|||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||
// Fabric API
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
|
||||
// LuaJ
|
||||
include(implementation("org.luaj:luaj-jse:3.0.1"))
|
||||
|
||||
// Configurate
|
||||
include(implementation("org.spongepowered:configurate-core:4.1.2"))
|
||||
include(implementation("org.spongepowered:configurate-gson:4.1.2"))
|
||||
include(implementation("io.leangen.geantyref:geantyref:1.3.16"))
|
||||
|
||||
// Adventure
|
||||
include(modImplementation("net.kyori:adventure-platform-fabric:6.2.0"))
|
||||
include(implementation("org.apache.commons:commons-text:1.13.0"))
|
||||
include(implementation("net.kyori:adventure-text-serializer-gson:4.18.0"))
|
||||
include(implementation("net.kyori:adventure-text-serializer-legacy:4.18.0"))
|
||||
include(implementation("org.luaj:luaj-jse:3.0.1"))
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
|
29
codestyle.xml
Normal file
29
codestyle.xml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<code_scheme name="Project" version="173">
|
||||
<JavaCodeStyleSettings>
|
||||
<option name="GENERATE_FINAL_LOCALS" value="true" />
|
||||
<option name="GENERATE_FINAL_PARAMETERS" value="true" />
|
||||
<option name="VISIBILITY" value="protected" />
|
||||
<option name="SPACE_BEFORE_OPENING_ANGLE_BRACKET_IN_TYPE_PARAMETER" value="true" />
|
||||
<option name="SPACE_BEFORE_DECONSTRUCTION_LIST" value="true" />
|
||||
</JavaCodeStyleSettings>
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="RIGHT_MARGIN" value="120" />
|
||||
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
|
||||
<option name="SPACE_WITHIN_BRACES" value="true" />
|
||||
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="true" />
|
||||
<option name="SPACE_BEFORE_METHOD_PARENTHESES" value="true" />
|
||||
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
|
||||
<option name="KEEP_SIMPLE_BLOCKS_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_MULTIPLE_EXPRESSIONS_IN_ONE_LINE" value="true" />
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
9
inspections.xml
Normal file
9
inspections.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="LocalCanBeFinal" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="REPORT_VARIABLES" value="true" />
|
||||
<option name="REPORT_PARAMETERS" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
|
@ -1,116 +1,86 @@
|
|||
package land.chipmunk.chipmunkmod;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import land.chipmunk.chipmunkmod.util.SharedVariables;
|
||||
import land.chipmunk.chipmunkmod.modules.KaboomCheck;
|
||||
import land.chipmunk.chipmunkmod.modules.SelfCare;
|
||||
import land.chipmunk.chipmunkmod.util.gson.BlockPosTypeAdapter;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import com.google.gson.Gson;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
// what the fuck is this indentation who is responsible for this nightmare
|
||||
public class ChipmunkMod implements ModInitializer {
|
||||
// This logger is used to write text to the console and the log file.
|
||||
// It is considered best practice to use your mod id as the logger's name.
|
||||
// That way, it's clear which mod wrote info, warnings, and errors.
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("chipmunkmod");
|
||||
public static Configuration CONFIG = new Configuration();
|
||||
public static final File CONFIG_DIR = new File("config");
|
||||
private static final File CONFIG_FILE = new File(CONFIG_DIR, "chipmunkmod.json");
|
||||
|
||||
public static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||
|
||||
|
||||
@Override
|
||||
public void onInitialize () {
|
||||
// This code runs as soon as Minecraft is in a mod-load-ready state.
|
||||
// However, some things (like resources) may still be uninitialized.
|
||||
// Proceed with mild caution.
|
||||
try {
|
||||
CONFIG = loadConfig();
|
||||
} catch (IOException exception) {
|
||||
throw new RuntimeException("Could not load the config", exception);
|
||||
}
|
||||
|
||||
KaboomCheck.INSTANCE.init();
|
||||
SelfCare.INSTANCE.init();
|
||||
|
||||
//save on quit owo
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.register(client -> {
|
||||
try {
|
||||
saveConfig();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to save config. Printing stacktrace.");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
LOGGER.info("Saved config!");
|
||||
});
|
||||
|
||||
LOGGER.info("Loaded ChipmunkMod (name3's fork)");
|
||||
}
|
||||
|
||||
public static Configuration loadConfig () throws IOException {
|
||||
CONFIG_DIR.mkdirs();
|
||||
|
||||
final Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(BlockPos.class, new BlockPosTypeAdapter())
|
||||
.serializeNulls()
|
||||
.create();
|
||||
final File file = CONFIG_FILE;
|
||||
|
||||
if (!file.exists()) {
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
InputStream is = new FileInputStream(file);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF8")));
|
||||
|
||||
Configuration configuration = gson.fromJson(reader, Configuration.class);
|
||||
if(configuration.bots.testbot.webhookUrl == null && configuration.testbotWebhook != null) {
|
||||
LOGGER.info("Updating testbot auth url location in config!");
|
||||
configuration.bots.testbot.webhookUrl = configuration.testbotWebhook;
|
||||
configuration.testbotWebhook = null;
|
||||
}
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public static void saveConfig() throws IOException {
|
||||
// to migrate old configs and avoid confusion on which field to use. Exclusion strategy should be removed once no one has the old auth location
|
||||
// in their configs anymore
|
||||
Gson otherGson = new GsonBuilder().serializeNulls().setLenient().setPrettyPrinting().addSerializationExclusionStrategy(new ExclusionStrategy() {
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return f.getName().equals("testbotWebhook");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
}).create();
|
||||
String defaultConfig = otherGson.toJson(CONFIG);
|
||||
BufferedWriter configWriter = new BufferedWriter(new FileWriter(CONFIG_FILE, Charset.forName("UTF8")));
|
||||
configWriter.write(defaultConfig);
|
||||
configWriter.close();
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod;
|
||||
|
||||
import land.chipmunk.chipmunkmod.config.ChipmunkModMigrations;
|
||||
import land.chipmunk.chipmunkmod.config.Name3ModMigrations;
|
||||
import land.chipmunk.chipmunkmod.config.Configuration;
|
||||
import land.chipmunk.chipmunkmod.modules.SelfCare;
|
||||
import land.chipmunk.chipmunkmod.util.configurate.ConfigurateUtilities;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.spongepowered.configurate.BasicConfigurationNode;
|
||||
import org.spongepowered.configurate.gson.GsonConfigurationLoader;
|
||||
import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
||||
import org.spongepowered.configurate.util.NamingSchemes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class ChipmunkMod implements ModInitializer {
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("ChipmunkMod");
|
||||
private static final Path CONFIG_PATH = FabricLoader.getInstance()
|
||||
.getConfigDir().resolve("chipmunkmod.json");
|
||||
public static Configuration CONFIG;
|
||||
|
||||
public static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||
|
||||
public static Configuration loadConfig () throws IOException {
|
||||
final ChipmunkModMigrations migrations = new ChipmunkModMigrations();
|
||||
final Name3ModMigrations name3Migrations = new Name3ModMigrations();
|
||||
final ObjectMapper.Factory customFactory = ObjectMapper.factoryBuilder()
|
||||
.defaultNamingScheme(NamingSchemes.CAMEL_CASE)
|
||||
.build();
|
||||
|
||||
final GsonConfigurationLoader loader = GsonConfigurationLoader.builder()
|
||||
.defaultOptions(options -> options
|
||||
.serializers(build -> build
|
||||
.registerAnnotatedObjects(customFactory)
|
||||
.registerAll(ConfigurateUtilities.customSerializers()))
|
||||
.shouldCopyDefaults(true))
|
||||
.indent(4)
|
||||
.path(CONFIG_PATH)
|
||||
.build();
|
||||
|
||||
// Configurate will create parent directories for us, so we don't need to do it
|
||||
final BasicConfigurationNode node = loader.load();
|
||||
if (node.empty()) { // Config empty, fill it with defaults
|
||||
final Configuration defaults = new Configuration();
|
||||
node.set(Configuration.class, defaults);
|
||||
migrations.setLatest(node);
|
||||
name3Migrations.setLatest(node);
|
||||
loader.save(node);
|
||||
|
||||
return defaults;
|
||||
}
|
||||
|
||||
if (migrations.migrate(node)) { // Migrated, write new config
|
||||
loader.save(node);
|
||||
}
|
||||
|
||||
if (name3Migrations.migrate(node)) {
|
||||
loader.save(node);
|
||||
}
|
||||
|
||||
return node.get(Configuration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitialize () {
|
||||
// This code runs as soon as Minecraft is in a mod-load-ready state.
|
||||
// However, some things (like resources) may still be uninitialized.
|
||||
// Proceed with mild caution.
|
||||
|
||||
try {
|
||||
CONFIG = loadConfig();
|
||||
} catch (final IOException exception) {
|
||||
throw new RuntimeException("Could not load the config", exception);
|
||||
}
|
||||
|
||||
SelfCare.INSTANCE.init();
|
||||
|
||||
LOGGER.info("Loaded ChipmunkMod (name3's fork)");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod;
|
||||
|
||||
import land.chipmunk.chipmunkmod.data.BlockArea;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
public class Configuration {
|
||||
public CommandManager commands = new CommandManager();
|
||||
public CommandCore core = new CommandCore();
|
||||
public Bots bots = new Bots();
|
||||
public CustomChat customChat = new CustomChat();
|
||||
public String autoSkinUsername = "off";
|
||||
// here so old configs can be migrated
|
||||
public String testbotWebhook = null;
|
||||
|
||||
public static class CommandManager {
|
||||
public String prefix = ".";
|
||||
}
|
||||
|
||||
public static class CommandCore {
|
||||
public BlockArea relativeArea = new BlockArea(new BlockPos(0, 0, 0), new BlockPos(15, 0, 15));
|
||||
}
|
||||
|
||||
public static class Bots {
|
||||
public BotInfo hbot = new BotInfo("#", null);
|
||||
public BotInfo sbot = new BotInfo(":", null);
|
||||
public BotInfo ubot = new BotInfo("\"", null);
|
||||
public BotInfo ubotdev = new BotInfo("d\"", null);
|
||||
public BotInfo chipmunk = new BotInfo("'", null);
|
||||
public ChomeNSBotInfo chomens = new ChomeNSBotInfo("*", null, null, null);
|
||||
public BotInfo fnfboyfriend = new BotInfo("~", null);
|
||||
public BotInfo nbot = new BotInfo("?", null);
|
||||
public BotInfo kittycorp = new BotInfo("^", null);
|
||||
public TestBotInfo testbot = new TestBotInfo("-", null);
|
||||
}
|
||||
|
||||
public static class ChomeNSBotInfo {
|
||||
public String prefix;
|
||||
public String key;
|
||||
public String authKey;
|
||||
public String formatKey;
|
||||
|
||||
public ChomeNSBotInfo (String prefix, String key, String authKey, String formatKey) {
|
||||
this.prefix = prefix;
|
||||
this.key = key;
|
||||
this.authKey = authKey;
|
||||
this.formatKey = formatKey;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestBotInfo {
|
||||
public String prefix;
|
||||
public String webhookUrl;
|
||||
|
||||
public TestBotInfo (String prefix, String webhookUrl) {
|
||||
this.prefix = prefix;
|
||||
this.webhookUrl = webhookUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BotInfo {
|
||||
public String prefix;
|
||||
public String key;
|
||||
|
||||
public BotInfo (String prefix, String key) {
|
||||
this.prefix = prefix;
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomChat {
|
||||
public JsonObject format;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,89 +1,91 @@
|
|||
package land.chipmunk.chipmunkmod.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.text.ClickEvent;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.Texts;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.command.CommandRegistryAccess;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import land.chipmunk.chipmunkmod.commands.*;
|
||||
|
||||
public class CommandManager {
|
||||
public CommandDispatcher<FabricClientCommandSource> dispatcher = new CommandDispatcher<>();
|
||||
public String prefix;
|
||||
|
||||
public static CommandManager INSTANCE;
|
||||
|
||||
public CommandManager (String prefix, CommandRegistryAccess commandRegistryAccess) {
|
||||
this.prefix = prefix;
|
||||
|
||||
TestCommand.register(this.dispatcher);
|
||||
CoreCommand.register(this.dispatcher);
|
||||
UsernameCommand.register(this.dispatcher);
|
||||
CloopCommand.register(this.dispatcher);
|
||||
ValidateCommand.register(this.dispatcher);
|
||||
ItemCommand.register(this.dispatcher, commandRegistryAccess);
|
||||
CustomChatCommand.register(this.dispatcher);
|
||||
EvalCommand.register(this.dispatcher);
|
||||
MusicCommand.register(this.dispatcher);
|
||||
RainbowNameCommand.register(this.dispatcher);
|
||||
SayCommand.register(this.dispatcher);
|
||||
AutoSkinCommand.register(this.dispatcher);
|
||||
ReloadConfigCommand.register(this.dispatcher);
|
||||
DebugCommand.register(this.dispatcher);
|
||||
SelfCareCommand.register(this.dispatcher);
|
||||
ClearAntiChatSpamQueueCommand.register(this.dispatcher);
|
||||
KickCommand.register(this.dispatcher);
|
||||
}
|
||||
|
||||
public void executeCommand (String command) {
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
final FabricClientCommandSource commandSource = (FabricClientCommandSource) client.getNetworkHandler().getCommandSource();
|
||||
|
||||
try {
|
||||
dispatcher.execute(command, commandSource);
|
||||
} catch (CommandSyntaxException e) {
|
||||
commandSource.sendError(Texts.toText(e.getRawMessage()));
|
||||
final Text context = getContext(e);
|
||||
if (context != null) commandSource.sendError(context);
|
||||
} catch (Exception e) {
|
||||
commandSource.sendError(Text.of(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public Text getContext (CommandSyntaxException exception) {
|
||||
final int _cursor = exception.getCursor();
|
||||
final String input = exception.getInput();
|
||||
|
||||
if (input == null || _cursor < 0) {
|
||||
return null;
|
||||
}
|
||||
final MutableText text = Text.literal("")
|
||||
.formatted(Formatting.GRAY);
|
||||
text.setStyle(text.getStyle().withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, prefix + input)));
|
||||
|
||||
final int cursor = Math.min(input.length(), _cursor);
|
||||
|
||||
if (cursor > CommandSyntaxException.CONTEXT_AMOUNT) {
|
||||
text.append(Text.literal("..."));
|
||||
}
|
||||
|
||||
text
|
||||
.append(Text.literal(input.substring(Math.max(0, cursor - CommandSyntaxException.CONTEXT_AMOUNT), cursor)))
|
||||
.append(Text.literal(input.substring(cursor)).formatted(Formatting.RED, Formatting.UNDERLINE))
|
||||
.append(Text.translatable("command.context.here").formatted(Formatting.RED, Formatting.ITALIC));
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public static LiteralArgumentBuilder<FabricClientCommandSource> literal (String name) { return LiteralArgumentBuilder.literal(name); }
|
||||
public static <T> RequiredArgumentBuilder<FabricClientCommandSource, T> argument (String name, ArgumentType<T> type) { return RequiredArgumentBuilder.argument(name, type); }
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import land.chipmunk.chipmunkmod.commands.*;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.command.CommandRegistryAccess;
|
||||
import net.minecraft.text.ClickEvent;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.Texts;
|
||||
import net.minecraft.util.Formatting;
|
||||
|
||||
public class CommandManager {
|
||||
public static CommandManager INSTANCE;
|
||||
public CommandDispatcher<FabricClientCommandSource> dispatcher = new CommandDispatcher<>();
|
||||
public String prefix;
|
||||
|
||||
public CommandManager (final String prefix, final CommandRegistryAccess commandRegistryAccess) {
|
||||
this.prefix = prefix;
|
||||
|
||||
TestCommand.register(this.dispatcher);
|
||||
CoreCommand.register(this.dispatcher);
|
||||
UsernameCommand.register(this.dispatcher);
|
||||
CloopCommand.register(this.dispatcher);
|
||||
ValidateCommand.register(this.dispatcher);
|
||||
ItemCommand.register(this.dispatcher, commandRegistryAccess);
|
||||
CustomChatCommand.register(this.dispatcher);
|
||||
EvalCommand.register(this.dispatcher);
|
||||
MusicCommand.register(this.dispatcher);
|
||||
RainbowNameCommand.register(this.dispatcher);
|
||||
SayCommand.register(this.dispatcher);
|
||||
AutoSkinCommand.register(this.dispatcher);
|
||||
ReloadConfigCommand.register(this.dispatcher);
|
||||
SelfCareCommand.register(this.dispatcher);
|
||||
KickCommand.register(this.dispatcher);
|
||||
}
|
||||
|
||||
public static LiteralArgumentBuilder<FabricClientCommandSource> literal (final String name) {
|
||||
return LiteralArgumentBuilder.literal(name);
|
||||
}
|
||||
|
||||
public static <T> RequiredArgumentBuilder<FabricClientCommandSource, T> argument (final String name, final ArgumentType<T> type) {
|
||||
return RequiredArgumentBuilder.argument(name, type);
|
||||
}
|
||||
|
||||
public void executeCommand (final String command) {
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
final FabricClientCommandSource commandSource = (FabricClientCommandSource) client.getNetworkHandler().getCommandSource();
|
||||
|
||||
try {
|
||||
dispatcher.execute(command, commandSource);
|
||||
} catch (final CommandSyntaxException e) {
|
||||
commandSource.sendError(Texts.toText(e.getRawMessage()));
|
||||
final Text context = getContext(e);
|
||||
if (context != null) commandSource.sendError(context);
|
||||
} catch (final Exception e) {
|
||||
commandSource.sendError(Text.of(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public Text getContext (final CommandSyntaxException exception) {
|
||||
final int _cursor = exception.getCursor();
|
||||
final String input = exception.getInput();
|
||||
|
||||
if (input == null || _cursor < 0) {
|
||||
return null;
|
||||
}
|
||||
final MutableText text = Text.literal("")
|
||||
.formatted(Formatting.GRAY);
|
||||
text.setStyle(text.getStyle().withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, prefix + input)));
|
||||
|
||||
final int cursor = Math.min(input.length(), _cursor);
|
||||
|
||||
if (cursor > CommandSyntaxException.CONTEXT_AMOUNT) {
|
||||
text.append(Text.literal("..."));
|
||||
}
|
||||
|
||||
text
|
||||
.append(Text.literal(input.substring(Math.max(0, cursor - CommandSyntaxException.CONTEXT_AMOUNT), cursor)))
|
||||
.append(Text.literal(input.substring(cursor)).formatted(Formatting.RED, Formatting.UNDERLINE))
|
||||
.append(Text.translatable("command.context.here").formatted(Formatting.RED, Formatting.ITALIC));
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,80 +8,81 @@ import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
|||
import net.minecraft.text.Text;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
public class LocationArgumentType implements ArgumentType<Object> {
|
||||
private static final Collection<String> EXAMPLES = Arrays.<String>asList("songs/amogus.mid", "images/cat.jpg", "videos/badapple.mp4");
|
||||
private static final Collection<String> EXAMPLES = Arrays.asList("songs/amogus.mid", "images/cat.jpg", "videos/badapple.mp4");
|
||||
|
||||
private static final SimpleCommandExceptionType OOB_FILEPATH = new SimpleCommandExceptionType(Text.translatable("The specified file path is outside of the allowed directory"));
|
||||
private final boolean allowsUrls;
|
||||
private final boolean allowsPaths;
|
||||
private final Path root;
|
||||
|
||||
private boolean allowsUrls = false;
|
||||
private boolean allowsPaths = false;
|
||||
private Path root;
|
||||
|
||||
private LocationArgumentType (boolean allowsUrls, boolean allowsPaths, Path root) {
|
||||
private LocationArgumentType (final boolean allowsUrls, final boolean allowsPaths, final Path root) {
|
||||
this.allowsUrls = allowsUrls;
|
||||
this.allowsPaths = allowsPaths;
|
||||
this.root = root.toAbsolutePath().normalize();
|
||||
}
|
||||
|
||||
public static LocationArgumentType location (Path rootPath) { return new LocationArgumentType(true, true, rootPath); }
|
||||
public static LocationArgumentType location (final Path rootPath) { return new LocationArgumentType(true, true, rootPath); }
|
||||
|
||||
public static LocationArgumentType url () { return new LocationArgumentType(true, false, null); }
|
||||
public static LocationArgumentType filepath (Path rootPath) { return new LocationArgumentType(false, true, rootPath); }
|
||||
|
||||
@Override
|
||||
public Object parse (StringReader reader) throws CommandSyntaxException {
|
||||
final String remaining = reader.getString().substring(reader.getCursor());
|
||||
if (allowsUrls && isUrlStart(remaining)) return parseUrl(reader);
|
||||
if (allowsPaths) return parsePath(reader);
|
||||
return null;
|
||||
}
|
||||
public static LocationArgumentType filepath (final Path rootPath) { return new LocationArgumentType(false, true, rootPath); }
|
||||
|
||||
public boolean isUrlStart (String string) { return string.startsWith("http://") || string.startsWith("https://") || string.startsWith("ftp://"); }
|
||||
|
||||
public URL parseUrl (StringReader reader) throws CommandSyntaxException {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
while (reader.canRead() && reader.peek() != ' ') {
|
||||
sb.append(reader.read());
|
||||
}
|
||||
|
||||
try {
|
||||
return new URL(sb.toString());
|
||||
} catch (MalformedURLException exception) {
|
||||
throw new SimpleCommandExceptionType(Text.literal(exception.getMessage())).create();
|
||||
}
|
||||
}
|
||||
|
||||
public Path parsePath (StringReader reader) throws CommandSyntaxException {
|
||||
final String pathString = reader.readString();
|
||||
final Path path = Path.of(root.toString(), pathString).toAbsolutePath().normalize();
|
||||
return path;
|
||||
}
|
||||
|
||||
private static Object getLocation (CommandContext<?> context, String name) {
|
||||
private static Object getLocation (final CommandContext<?> context, final String name) {
|
||||
return context.getArgument(name, Object.class);
|
||||
}
|
||||
|
||||
public static URL getUrl (CommandContext<?> context, String name) {
|
||||
public static URL getUrl (final CommandContext<?> context, final String name) {
|
||||
final Object location = getLocation(context, name);
|
||||
if (location instanceof URL) return (URL) location;
|
||||
try {
|
||||
if (location instanceof Path) return new URL("file", "", -1, location.toString());
|
||||
} catch (MalformedURLException ignored) {
|
||||
if (location instanceof Path) return new URI("file", "", "", -1, location.toString(), "", "").toURL();
|
||||
} catch (final MalformedURLException | URISyntaxException ignored) {
|
||||
return null; // The real question is whether this will actually ever get called
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Path getPath (CommandContext<?> context, String name) {
|
||||
public static Path getPath (final CommandContext<?> context, final String name) {
|
||||
final Object location = getLocation(context, name);
|
||||
if (location instanceof Path) return (Path) location;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse (final StringReader reader) throws CommandSyntaxException {
|
||||
final String remaining = reader.getString().substring(reader.getCursor());
|
||||
if (allowsUrls && isUrlStart(remaining)) return parseUrl(reader);
|
||||
if (allowsPaths) return parsePath(reader);
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isUrlStart (final String string) { return string.startsWith("http://") || string.startsWith("https://") || string.startsWith("ftp://"); }
|
||||
|
||||
public URL parseUrl (final StringReader reader) throws CommandSyntaxException {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
while (reader.canRead() && reader.peek() != ' ') {
|
||||
sb.append(reader.read());
|
||||
}
|
||||
|
||||
try {
|
||||
return new URI(sb.toString()).toURL();
|
||||
} catch (final MalformedURLException | URISyntaxException exception) {
|
||||
throw new SimpleCommandExceptionType(Text.literal(exception.getMessage())).create();
|
||||
}
|
||||
}
|
||||
|
||||
public Path parsePath (final StringReader reader) throws CommandSyntaxException {
|
||||
final String pathString = reader.readString();
|
||||
return Path.of(root.toString(), pathString).toAbsolutePath().normalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getExamples () { return EXAMPLES; }
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package land.chipmunk.chipmunkmod.command.arguments;
|
||||
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import java.util.Collection;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
public class TimestampArgumentType implements ArgumentType<Long> {
|
||||
private static final Collection<String> EXAMPLES = Arrays.<String>asList("0:01", "1:23", "6:09");
|
||||
private static final Collection<String> EXAMPLES = Arrays.asList("0:01", "1:23", "6:09");
|
||||
|
||||
private TimestampArgumentType () {
|
||||
}
|
||||
|
@ -15,7 +16,7 @@ public class TimestampArgumentType implements ArgumentType<Long> {
|
|||
public static TimestampArgumentType timestamp () { return new TimestampArgumentType(); }
|
||||
|
||||
@Override
|
||||
public Long parse (StringReader reader) throws CommandSyntaxException {
|
||||
public Long parse (final StringReader reader) throws CommandSyntaxException {
|
||||
long seconds = 0L;
|
||||
long minutes = 0L;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
|||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class AutoSkinCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("autoskin")
|
||||
.then(
|
||||
|
@ -23,7 +23,7 @@ public class AutoSkinCommand {
|
|||
);
|
||||
}
|
||||
|
||||
public static int execute(CommandContext<FabricClientCommandSource> context) {
|
||||
public static int execute (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final String username = getString(context, "username");
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.commands;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import land.chipmunk.chipmunkmod.util.Chat;
|
||||
import land.chipmunk.chipmunkmod.util.Executor;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class ClearAntiChatSpamQueueCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
final ClearAntiChatSpamQueueCommand instance = new ClearAntiChatSpamQueueCommand();
|
||||
dispatcher.register(
|
||||
literal("clearantichatspamqueue")
|
||||
.executes(instance::run)
|
||||
);
|
||||
}
|
||||
|
||||
public int run(CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
List<Runnable> runnables = Executor.antiChatSpamService.shutdownNow();
|
||||
Executor.antiChatSpamService = Executors.newFixedThreadPool(1);
|
||||
Chat.sendGreen("Stopped " + runnables.size() + " chat messages from getting recieved!");
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -5,23 +5,25 @@ import com.mojang.brigadier.CommandDispatcher;
|
|||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
import static com.mojang.brigadier.arguments.LongArgumentType.longArg;
|
||||
import static com.mojang.brigadier.arguments.LongArgumentType.getLong;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
|
||||
import land.chipmunk.chipmunkmod.modules.CommandLoopManager;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
import land.chipmunk.chipmunkmod.modules.CommandLoopManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
||||
import static com.mojang.brigadier.arguments.LongArgumentType.getLong;
|
||||
import static com.mojang.brigadier.arguments.LongArgumentType.longArg;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class CloopCommand {
|
||||
private static final DynamicCommandExceptionType INVALID_CLOOP_ID_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("Invalid cloop id: %s", Text.literal(String.valueOf(id))));
|
||||
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("cloop")
|
||||
.then(
|
||||
|
@ -52,18 +54,18 @@ public class CloopCommand {
|
|||
);
|
||||
}
|
||||
|
||||
public static int addCloop (CommandContext<FabricClientCommandSource> context) {
|
||||
public static int addCloop (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final long interval = getLong(context, "interval");
|
||||
final String command = getString(context, "command");
|
||||
|
||||
int id = CommandLoopManager.INSTANCE.loopCommand(command, interval);
|
||||
final int id = CommandLoopManager.INSTANCE.loopCommand(command, interval);
|
||||
|
||||
source.sendFeedback(Text.translatable("Successfully created a loop for command '%s' with id %s", Text.literal(command), Text.literal(String.valueOf(id))));
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int removeCloop (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
public static int removeCloop (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final CommandLoopManager manager = CommandLoopManager.INSTANCE;
|
||||
final int id = getInteger(context, "id");
|
||||
|
@ -76,7 +78,7 @@ public class CloopCommand {
|
|||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int clearCloops (CommandContext<FabricClientCommandSource> context) {
|
||||
public static int clearCloops (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final CommandLoopManager manager = CommandLoopManager.INSTANCE;
|
||||
|
||||
|
@ -86,13 +88,13 @@ public class CloopCommand {
|
|||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int listCloops (CommandContext<FabricClientCommandSource> context) {
|
||||
public static int listCloops (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final List<CommandLoopManager.CommandLoop> loops = CommandLoopManager.INSTANCE.commandLoops;
|
||||
|
||||
int id = 0;
|
||||
for (CommandLoopManager.CommandLoop loop : loops) {
|
||||
source.sendFeedback(Text.translatable("%s: %s (%s)", Text.literal(String.valueOf(id)), Text.literal(loop.command), Text.literal(String.valueOf(loop.interval))));
|
||||
for (final CommandLoopManager.CommandLoop loop : loops) {
|
||||
source.sendFeedback(Text.translatable("%s: %s (%s)", Text.literal(String.valueOf(id)), Text.literal(loop.command), Text.literal(String.valueOf(loop.interval))));
|
||||
id++;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,106 +1,105 @@
|
|||
package land.chipmunk.chipmunkmod.commands;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
|
||||
import static com.mojang.brigadier.arguments.BoolArgumentType.bool;
|
||||
import static com.mojang.brigadier.arguments.BoolArgumentType.getBool;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
|
||||
import land.chipmunk.chipmunkmod.util.TextUtilities;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import land.chipmunk.chipmunkmod.modules.CommandCore;
|
||||
|
||||
public class CoreCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("core")
|
||||
.then(
|
||||
literal("run")
|
||||
.then(
|
||||
argument("command", greedyString())
|
||||
.executes(c -> run(c))
|
||||
)
|
||||
)
|
||||
|
||||
.then(
|
||||
literal("runTracked")
|
||||
.then(
|
||||
argument("command", greedyString())
|
||||
.executes(c -> runTracked(c))
|
||||
)
|
||||
)
|
||||
|
||||
.then(literal("refill").executes(c -> refill(c)))
|
||||
.then(literal("move").executes(c -> move(c)))
|
||||
|
||||
.then(
|
||||
literal("runFillCommand")
|
||||
.then(
|
||||
argument("enabled", bool())
|
||||
.executes(c -> runFillCommand(c))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static int run (CommandContext<FabricClientCommandSource> context) {
|
||||
CommandCore.INSTANCE.run(getString(context, "command"));
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int runTracked (CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final String command = getString(context, "command");
|
||||
|
||||
final CompletableFuture<NbtCompound> future = CommandCore.INSTANCE.runTracked(command);
|
||||
future.thenApply(tag -> {
|
||||
try {
|
||||
final String output = tag.getString("LastOutput");
|
||||
if (output != null) source.sendFeedback(TextUtilities.fromJson(output));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return tag;
|
||||
});
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int refill (CommandContext<FabricClientCommandSource> context) {
|
||||
CommandCore.INSTANCE.refill();
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int move (CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
CommandCore.INSTANCE.move(source.getClient().player.getPos());
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int runFillCommand(CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final boolean bool = getBool(context, "enabled");
|
||||
|
||||
CommandCore.INSTANCE.runFillCommand = bool;
|
||||
|
||||
source.sendFeedback(Text.literal("Running fill commands are now " + (bool ? "enabled" : "disabled")));
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.commands;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import land.chipmunk.chipmunkmod.modules.CommandCore;
|
||||
import land.chipmunk.chipmunkmod.util.TextUtilities;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.mojang.brigadier.arguments.BoolArgumentType.bool;
|
||||
import static com.mojang.brigadier.arguments.BoolArgumentType.getBool;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class CoreCommand {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("core")
|
||||
.then(
|
||||
literal("run")
|
||||
.then(
|
||||
argument("command", greedyString())
|
||||
.executes(c -> run(c))
|
||||
)
|
||||
)
|
||||
|
||||
.then(
|
||||
literal("runTracked")
|
||||
.then(
|
||||
argument("command", greedyString())
|
||||
.executes(c -> runTracked(c))
|
||||
)
|
||||
)
|
||||
|
||||
.then(literal("refill").executes(c -> refill(c)))
|
||||
.then(literal("move").executes(c -> move(c)))
|
||||
|
||||
.then(
|
||||
literal("runFillCommand")
|
||||
.then(
|
||||
argument("enabled", bool())
|
||||
.executes(c -> runFillCommand(c))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static int run (final CommandContext<FabricClientCommandSource> context) {
|
||||
CommandCore.INSTANCE.run(getString(context, "command"));
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int runTracked (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final String command = getString(context, "command");
|
||||
|
||||
final CompletableFuture<NbtCompound> future = CommandCore.INSTANCE.runTracked(command);
|
||||
future.thenApply(tag -> {
|
||||
try {
|
||||
final String output = tag.getString("LastOutput");
|
||||
if (output != null) source.sendFeedback(TextUtilities.fromJson(output));
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return tag;
|
||||
});
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int refill (final CommandContext<FabricClientCommandSource> context) {
|
||||
CommandCore.INSTANCE.refill();
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int move (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
CommandCore.INSTANCE.move(source.getClient().player.getPos());
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int runFillCommand (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final boolean bool = getBool(context, "enabled");
|
||||
|
||||
CommandCore.INSTANCE.runFillCommand = bool;
|
||||
|
||||
source.sendFeedback(Text.literal("Running fill commands is now " + (bool ? "enabled" : "disabled")));
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@ package land.chipmunk.chipmunkmod.commands;
|
|||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import land.chipmunk.chipmunkmod.modules.CustomChat;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import static com.mojang.brigadier.arguments.BoolArgumentType.bool;
|
||||
|
@ -15,15 +17,17 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
|||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class CustomChatCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
private static final GsonComponentSerializer GSON = GsonComponentSerializer.gson();
|
||||
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("customchat")
|
||||
.then(
|
||||
literal("enabled")
|
||||
.then(
|
||||
argument("boolean", bool())
|
||||
.executes(CustomChatCommand::enabled)
|
||||
)
|
||||
.then(
|
||||
argument("boolean", bool())
|
||||
.executes(CustomChatCommand::enabled)
|
||||
)
|
||||
)
|
||||
.then(
|
||||
literal("format")
|
||||
|
@ -35,7 +39,7 @@ public class CustomChatCommand {
|
|||
);
|
||||
}
|
||||
|
||||
public static int enabled (CommandContext<FabricClientCommandSource> context) {
|
||||
public static int enabled (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final boolean bool = getBool(context, "boolean");
|
||||
CustomChat.INSTANCE.enabled = bool;
|
||||
|
@ -44,10 +48,10 @@ public class CustomChatCommand {
|
|||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int setFormat (CommandContext<FabricClientCommandSource> context) {
|
||||
public static int setFormat (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final String format = getString(context, "format");
|
||||
CustomChat.INSTANCE.format = format;
|
||||
CustomChat.INSTANCE.format = GSON.deserializeOr(format, ChipmunkMod.CONFIG.customChat.format);
|
||||
source.sendFeedback(Text.literal("Set the custom chat format to: " + format));
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.commands;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||
import land.chipmunk.chipmunkmod.util.Debug;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.string;
|
||||
|
||||
public class DebugCommand {
|
||||
public static SuggestionProvider<FabricClientCommandSource> knownSuggestions = (context, builder) -> {
|
||||
Debug.known.stream()
|
||||
.filter(option -> option.startsWith(builder.getRemaining().toLowerCase()))
|
||||
.forEach(builder::suggest);
|
||||
return builder.buildFuture();
|
||||
};
|
||||
public static SuggestionProvider<FabricClientCommandSource> selectedSuggestions = (context, builder) -> {
|
||||
Debug.selected.stream()
|
||||
.filter(option -> option.startsWith(builder.getRemaining().toLowerCase()))
|
||||
.forEach(builder::suggest);
|
||||
return builder.buildFuture();
|
||||
};
|
||||
public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("debug")
|
||||
.then(literal("add")
|
||||
.then(argument("caller", string())
|
||||
.suggests(knownSuggestions)
|
||||
.executes(DebugCommand::add)))
|
||||
.then(literal("remove")
|
||||
.then(argument("caller", string())
|
||||
.suggests(selectedSuggestions)
|
||||
.executes(DebugCommand::remove)))
|
||||
.then(literal("clear")
|
||||
.executes(DebugCommand::clear))
|
||||
);
|
||||
}
|
||||
|
||||
public static int add(CommandContext<FabricClientCommandSource> context) {
|
||||
String caller = context.getArgument("caller", String.class);
|
||||
Debug.selected.add(caller);
|
||||
context.getSource().sendFeedback(Text.literal("Added ").append(Text.literal(caller).formatted(Formatting.YELLOW)).append(Text.literal(" to the debug list!")));
|
||||
return 0;
|
||||
}
|
||||
public static int remove(CommandContext<FabricClientCommandSource> context) {
|
||||
String caller = context.getArgument("caller", String.class);
|
||||
Debug.selected.remove(caller);
|
||||
context.getSource().sendFeedback(Text.literal("Removed ").append(Text.literal(caller).formatted(Formatting.YELLOW)).append(Text.literal(" from the debug list!")));
|
||||
return 0;
|
||||
}
|
||||
public static int clear(CommandContext<FabricClientCommandSource> context) {
|
||||
Debug.selected = new ArrayList<>();
|
||||
context.getSource().sendFeedback(Text.literal("Cleared the debug list!"));
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
|||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class EvalCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("eval")
|
||||
.then(literal("java")
|
||||
|
@ -47,10 +47,10 @@ public class EvalCommand {
|
|||
globals.set("context", CoerceJavaToLua.coerce(context));
|
||||
globals.set("class", CoerceJavaToLua.coerce(Class.class));
|
||||
|
||||
LuaValue chunk = globals.load(code);
|
||||
final LuaValue chunk = globals.load(code);
|
||||
|
||||
context.getSource().sendFeedback(Text.literal(chunk.call().toString()).formatted(Formatting.GREEN));
|
||||
} catch (Exception e) {
|
||||
} catch (final Exception e) {
|
||||
context.getSource().sendError(Text.literal(e.toString()));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,21 +4,22 @@ import com.mojang.brigadier.Command;
|
|||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
|
||||
import static net.minecraft.command.argument.ItemStackArgumentType.itemStack;
|
||||
import static net.minecraft.command.argument.ItemStackArgumentType.getItemStackArgument;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.command.CommandRegistryAccess;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket;
|
||||
import net.minecraft.command.CommandRegistryAccess;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
import static net.minecraft.command.argument.ItemStackArgumentType.getItemStackArgument;
|
||||
import static net.minecraft.command.argument.ItemStackArgumentType.itemStack;
|
||||
|
||||
public class ItemCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher, CommandRegistryAccess commandRegistryAccess) {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher, final CommandRegistryAccess commandRegistryAccess) {
|
||||
dispatcher.register(
|
||||
literal("item")
|
||||
.then(
|
||||
|
@ -32,17 +33,17 @@ public class ItemCommand {
|
|||
);
|
||||
}
|
||||
|
||||
public static int setItem (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
public static int setItem (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
return setItem(context, getInteger(context, "count"));
|
||||
}
|
||||
|
||||
public static int setItem (CommandContext<FabricClientCommandSource> context, int count) throws CommandSyntaxException {
|
||||
public static int setItem (final CommandContext<FabricClientCommandSource> context, final int count) throws CommandSyntaxException {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final MinecraftClient client = source.getClient();
|
||||
|
||||
final ItemStack stack = getItemStackArgument(context, "item").createStack(count, false);
|
||||
|
||||
int slot = 36 + client.player.getInventory().selectedSlot;
|
||||
final int slot = 36 + client.player.getInventory().selectedSlot;
|
||||
|
||||
client.getNetworkHandler().getConnection().send(new CreativeInventoryActionC2SPacket(slot, stack));
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
|||
import land.chipmunk.chipmunkmod.modules.CommandCore;
|
||||
|
||||
public class KickCommand {
|
||||
// All methods here are reverse engineered from bots or players who abused them.
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("kick")
|
||||
|
|
|
@ -8,12 +8,12 @@ import land.chipmunk.chipmunkmod.command.CommandManager;
|
|||
import land.chipmunk.chipmunkmod.modules.SongPlayer;
|
||||
import land.chipmunk.chipmunkmod.song.Song;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
|
@ -40,10 +40,10 @@ public class MusicCommand {
|
|||
private static final SimpleCommandExceptionType OOB_TIMESTAMP = new SimpleCommandExceptionType(Text.translatable("Invalid timestamp for the current song"));
|
||||
private static final SimpleCommandExceptionType DIRECTORY_DOES_NOT_EXIST = new SimpleCommandExceptionType(Text.translatable("The specified directory does not exist"));
|
||||
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
final MusicCommand instance = new MusicCommand();
|
||||
|
||||
Path root = Path.of(SongPlayer.SONG_DIR.getPath());
|
||||
final Path root = Path.of(SongPlayer.SONG_DIR.getPath());
|
||||
|
||||
dispatcher.register(
|
||||
literal("music")
|
||||
|
@ -111,7 +111,7 @@ public class MusicCommand {
|
|||
);
|
||||
}
|
||||
|
||||
public int play (CommandContext<FabricClientCommandSource> context) {
|
||||
public int play (final CommandContext<FabricClientCommandSource> context) {
|
||||
final SongPlayer songPlayer = SongPlayer.INSTANCE;
|
||||
|
||||
final Path path = getPath(context, "location");
|
||||
|
@ -122,7 +122,7 @@ public class MusicCommand {
|
|||
return 1;
|
||||
}
|
||||
|
||||
public int stop (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
public int stop (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final SongPlayer songPlayer = SongPlayer.INSTANCE;
|
||||
|
||||
|
@ -130,24 +130,24 @@ public class MusicCommand {
|
|||
|
||||
songPlayer.stopPlaying();
|
||||
songPlayer.songQueue.clear();
|
||||
source.sendFeedback(Text.literal("Stopped music playback").formatted(Formatting.GREEN));
|
||||
source.sendFeedback(Text.literal("Stopped music playback").formatted(Formatting.WHITE));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int skip (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
public int skip (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final SongPlayer songPlayer = SongPlayer.INSTANCE;
|
||||
|
||||
if (songPlayer.currentSong == null) throw NO_SONG_IS_CURRENTLY_PLAYING.create();
|
||||
|
||||
songPlayer.stopPlaying();
|
||||
source.sendFeedback(Text.literal("Skipped the current song").formatted(Formatting.GREEN));
|
||||
source.sendFeedback(Text.literal("Skipped the current song").formatted(Formatting.WHITE));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int pause (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
public int pause (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final SongPlayer songPlayer = SongPlayer.INSTANCE;
|
||||
final Song currentSong = songPlayer.currentSong;
|
||||
|
@ -165,7 +165,7 @@ public class MusicCommand {
|
|||
return 1;
|
||||
}
|
||||
|
||||
public int list (Path path) throws CommandSyntaxException {
|
||||
public int list (final Path path) throws CommandSyntaxException {
|
||||
final CommandManager commandManager = CommandManager.INSTANCE;
|
||||
|
||||
final String prefix = commandManager.prefix;
|
||||
|
@ -175,19 +175,20 @@ public class MusicCommand {
|
|||
if (filenames == null) throw DIRECTORY_DOES_NOT_EXIST.create();
|
||||
|
||||
final Path root = Path.of(SongPlayer.SONG_DIR.getAbsoluteFile().getPath()).toAbsolutePath();
|
||||
String relativePath;
|
||||
if (path.getNameCount() - root.getNameCount() > 0) relativePath = path.subpath(root.getNameCount(), path.getNameCount()).toString();
|
||||
final String relativePath;
|
||||
if (path.getNameCount() - root.getNameCount() > 0)
|
||||
relativePath = path.subpath(root.getNameCount(), path.getNameCount()).toString();
|
||||
else relativePath = "";
|
||||
|
||||
final List<Component> directories = new ArrayList<>();
|
||||
final List<Component> files = new ArrayList<>();
|
||||
int i = 0;
|
||||
|
||||
for (String filename : filenames) {
|
||||
for (final String filename : filenames) {
|
||||
final File file = new File(directory, filename);
|
||||
if (!file.isDirectory()) continue;
|
||||
|
||||
final NamedTextColor color = (i++ & 1) == 0 ? NamedTextColor.DARK_GREEN : NamedTextColor.GREEN;
|
||||
final TextColor color = (i++ & 1) == 0 ? TextColor.fromHexString("#ffccee") : TextColor.fromHexString("#ff99dd");
|
||||
|
||||
final Path relativeFilepath = Path.of(relativePath, filename);
|
||||
final String escapedPath = escapePath(relativeFilepath.toString());
|
||||
|
@ -199,11 +200,11 @@ public class MusicCommand {
|
|||
);
|
||||
}
|
||||
|
||||
for (String filename : filenames) {
|
||||
for (final String filename : filenames) {
|
||||
final File file = new File(directory, filename);
|
||||
if (file.isDirectory()) continue;
|
||||
|
||||
final NamedTextColor color = (i++ & 1) == 0 ? NamedTextColor.DARK_GREEN : NamedTextColor.GREEN;
|
||||
final TextColor color = (i++ & 1) == 0 ? TextColor.fromHexString("#ffccee") : TextColor.fromHexString("#ff99dd");
|
||||
|
||||
final Path relativeFilepath = Path.of(relativePath, filename);
|
||||
final String escapedPath = escapePath(relativeFilepath.toString());
|
||||
|
@ -218,18 +219,18 @@ public class MusicCommand {
|
|||
final ArrayList<Component> mergedList = new ArrayList<>();
|
||||
mergedList.addAll(directories);
|
||||
mergedList.addAll(files);
|
||||
final Component component = Component.translatable("Songs - %s", Component.join(JoinConfiguration.separator(Component.space()), mergedList)).color(NamedTextColor.GREEN);
|
||||
final Component component = Component.translatable("Songs - %s", Component.join(JoinConfiguration.separator(Component.space()), mergedList)).color(NamedTextColor.WHITE);
|
||||
|
||||
((Audience) MinecraftClient.getInstance().player).sendMessage(component);
|
||||
MinecraftClient.getInstance().player.sendMessage(component);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO: Move this into some utility class, as it is more related to brigadier strings in general than to the list command in specific
|
||||
private String escapePath (String path) {
|
||||
private String escapePath (final String path) {
|
||||
final StringBuilder sb = new StringBuilder("'");
|
||||
|
||||
for (char character : path.toCharArray()) {
|
||||
for (final char character : path.toCharArray()) {
|
||||
if (character == '\'' || character == '\\') sb.append('\\');
|
||||
sb.append(character);
|
||||
}
|
||||
|
@ -238,7 +239,7 @@ public class MusicCommand {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
public int toggleLoop (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
public int toggleLoop (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final SongPlayer songPlayer = SongPlayer.INSTANCE;
|
||||
final Song currentSong = songPlayer.currentSong;
|
||||
|
@ -253,7 +254,7 @@ public class MusicCommand {
|
|||
}
|
||||
|
||||
|
||||
public int loop (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
public int loop (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final SongPlayer songPlayer = SongPlayer.INSTANCE;
|
||||
final Song currentSong = songPlayer.currentSong;
|
||||
|
@ -269,7 +270,7 @@ public class MusicCommand {
|
|||
return 1;
|
||||
}
|
||||
|
||||
public int gotoCommand (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
public int gotoCommand (final CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final SongPlayer songPlayer = SongPlayer.INSTANCE;
|
||||
final Song currentSong = songPlayer.currentSong;
|
||||
|
@ -281,12 +282,12 @@ public class MusicCommand {
|
|||
|
||||
currentSong.setTime(millis);
|
||||
|
||||
source.sendFeedback(Text.translatable("Set the current time of the song to %s", songPlayer.formatTime(millis)));
|
||||
MinecraftClient.getInstance().player.sendMessage(Component.translatable("Set the current time of the song to %s", songPlayer.formatTime(millis)));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int useCore (CommandContext<FabricClientCommandSource> context) {
|
||||
public int useCore (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final boolean enabled = getBool(context, "boolean");
|
||||
|
@ -298,7 +299,7 @@ public class MusicCommand {
|
|||
return 1;
|
||||
}
|
||||
|
||||
public int actionbar (CommandContext<FabricClientCommandSource> context) {
|
||||
public int actionbar (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final boolean enabled = getBool(context, "boolean");
|
||||
|
@ -310,7 +311,7 @@ public class MusicCommand {
|
|||
return 1;
|
||||
}
|
||||
|
||||
public int pitch (CommandContext<FabricClientCommandSource> context) {
|
||||
public int pitch (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final float pitch = getFloat(context, "pitch");
|
||||
|
@ -321,7 +322,7 @@ public class MusicCommand {
|
|||
Text.translatable(
|
||||
"Set the pitch to: %s",
|
||||
Text.literal(String.valueOf(pitch))
|
||||
).formatted(Formatting.GREEN)
|
||||
).formatted(Formatting.WHITE)
|
||||
);
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -15,7 +15,7 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
|||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class RainbowNameCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("rainbowname")
|
||||
.then(
|
||||
|
@ -35,7 +35,7 @@ public class RainbowNameCommand {
|
|||
);
|
||||
}
|
||||
|
||||
public static int enabled (CommandContext<FabricClientCommandSource> context) {
|
||||
public static int enabled (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final boolean bool = getBool(context, "boolean");
|
||||
|
@ -51,7 +51,7 @@ public class RainbowNameCommand {
|
|||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int setName (CommandContext<FabricClientCommandSource> context) {
|
||||
public static int setName (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final String name = getString(context, "name");
|
||||
|
|
|
@ -5,7 +5,6 @@ import com.mojang.brigadier.CommandDispatcher;
|
|||
import com.mojang.brigadier.context.CommandContext;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.modules.CommandCore;
|
||||
import land.chipmunk.chipmunkmod.modules.CustomChat;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
|
@ -14,24 +13,22 @@ import java.io.IOException;
|
|||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class ReloadConfigCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("reloadconfig")
|
||||
.executes(ReloadConfigCommand::reload)
|
||||
);
|
||||
}
|
||||
|
||||
public static int reload(CommandContext<FabricClientCommandSource> context) {
|
||||
public static int reload (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
try {
|
||||
ChipmunkMod.CONFIG = ChipmunkMod.loadConfig();
|
||||
|
||||
CustomChat.INSTANCE.reloadFormat();
|
||||
CommandCore.INSTANCE.reloadRelativeArea();
|
||||
|
||||
source.sendFeedback(Text.literal("Successfully reloaded the config"));
|
||||
} catch (IOException e) {
|
||||
} catch (final IOException e) {
|
||||
source.sendError(Text.literal("Could not load config, check the logs for stacktrace"));
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
|||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class SayCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("say")
|
||||
.then(
|
||||
|
@ -22,7 +22,7 @@ public class SayCommand {
|
|||
);
|
||||
}
|
||||
|
||||
public static int say (CommandContext<FabricClientCommandSource> context) {
|
||||
public static int say (final CommandContext<FabricClientCommandSource> context) {
|
||||
Chat.sendChatMessage(getString(context, "message"), true);
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
|
|
|
@ -2,20 +2,10 @@ package land.chipmunk.chipmunkmod.commands;
|
|||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.modules.SelfCare;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.PlayerListEntry;
|
||||
import net.minecraft.text.Text;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.mojang.brigadier.arguments.BoolArgumentType.bool;
|
||||
import static com.mojang.brigadier.arguments.BoolArgumentType.getBool;
|
||||
|
@ -23,9 +13,7 @@ import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
|||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class SelfCareCommand {
|
||||
private static final Logger log = LoggerFactory.getLogger(SelfCareCommand.class);
|
||||
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("selfcare")
|
||||
.then(
|
||||
|
@ -49,18 +37,10 @@ public class SelfCareCommand {
|
|||
.executes(m -> setSelfCare(m, "cspy"))
|
||||
)
|
||||
)
|
||||
.then(
|
||||
literal("icu")
|
||||
.then(
|
||||
argument("boolean", bool())
|
||||
.executes(m -> setSelfCare(m, "icu"))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// setSelfCare is probably not a good name for this
|
||||
public static int setSelfCare (CommandContext<FabricClientCommandSource> context, String type) {
|
||||
public static int setSelfCare (final CommandContext<FabricClientCommandSource> context, final String type) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
final boolean bool = getBool(context, "boolean");
|
||||
|
||||
|
@ -77,10 +57,6 @@ public class SelfCareCommand {
|
|||
SelfCare.INSTANCE.cspyEnabled = bool;
|
||||
source.sendFeedback(Text.literal("The CommandSpy self care is now " + (bool ? "enabled" : "disabled")));
|
||||
}
|
||||
case "icu" -> {
|
||||
SelfCare.INSTANCE.icuEnabled = bool;
|
||||
source.sendFeedback(Text.literal("The iControlU self care is now " + (bool ? "enabled" : "disabled")));
|
||||
}
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
package land.chipmunk.chipmunkmod.commands;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class TestCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("test")
|
||||
.executes(c -> helloWorld(c))
|
||||
);
|
||||
}
|
||||
|
||||
public static int helloWorld (CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
source.sendFeedback(Text.literal("Hello, world!"));
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.commands;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class TestCommand {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("test")
|
||||
.executes(c -> helloWorld(c))
|
||||
);
|
||||
}
|
||||
|
||||
public static int helloWorld (final CommandContext<FabricClientCommandSource> context) {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
source.sendFeedback(Text.literal("Hello, world!"));
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +1,100 @@
|
|||
package land.chipmunk.chipmunkmod.commands;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.util.SharedVariables;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.TitleScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.ConnectScreen;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
import net.minecraft.client.network.ServerAddress;
|
||||
import net.minecraft.client.session.Session;
|
||||
import net.minecraft.text.Text;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
import java.util.Optional;
|
||||
import land.chipmunk.chipmunkmod.mixin.MinecraftClientAccessor;
|
||||
|
||||
public class UsernameCommand {
|
||||
private static final SimpleCommandExceptionType USERNAME_TOO_LONG = new SimpleCommandExceptionType(Text.translatable("The specified username is longer than 16 characters"));
|
||||
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("username")
|
||||
.then(
|
||||
literal("set")
|
||||
.then(
|
||||
argument("username", greedyString())
|
||||
.executes(c -> updateUsername(c))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static int updateUsername (CommandContext<FabricClientCommandSource> context) throws CommandSyntaxException {
|
||||
final String username = getString(context, "username");
|
||||
if (username.length() > 16) throw USERNAME_TOO_LONG.create();
|
||||
return updateSession(context, username);
|
||||
}
|
||||
|
||||
public static int updateSession (CommandContext<FabricClientCommandSource> context, String username) throws CommandSyntaxException {
|
||||
final FabricClientCommandSource source = context.getSource();
|
||||
|
||||
final MinecraftClient client = source.getClient();
|
||||
|
||||
// TODO: Put this in a separate class
|
||||
final ServerInfo info = client.getCurrentServerEntry();
|
||||
client.world.disconnect();
|
||||
client.disconnect();
|
||||
ConnectScreen.connect(new TitleScreen(), client, ServerAddress.parse(info.address), info, false, null);
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.commands;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
import land.chipmunk.chipmunkmod.mixin.ClientCommonNetworkHandlerAccessor;
|
||||
import land.chipmunk.chipmunkmod.mixin.MinecraftClientAccessor;
|
||||
import land.chipmunk.chipmunkmod.util.RandomUtilities;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.TitleScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.ConnectScreen;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ServerAddress;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
import net.minecraft.client.session.Session;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Uuids;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
|
||||
public class UsernameCommand {
|
||||
private static final SimpleCommandExceptionType USERNAME_TOO_LONG = new SimpleCommandExceptionType(Text.translatable("The specified username is longer than 16 characters"));
|
||||
private static final char[] PREMIUM_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"
|
||||
.toCharArray();
|
||||
private static final char SECTION_CHAR = '§';
|
||||
|
||||
private static final Session ORIGINAL_SESSION = MinecraftClient.getInstance().getSession();
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(literal("username")
|
||||
.then(literal("set")
|
||||
.then(argument("username", greedyString())
|
||||
.executes(c -> changeOffline(c, getString(c, "username")))))
|
||||
.then(literal("revert")
|
||||
.executes(c -> changeSession(c, ORIGINAL_SESSION)))
|
||||
|
||||
.then(literal("random")
|
||||
.then(literal("blank")
|
||||
.executes(c -> changeOffline(c, RandomUtilities.emptyUsername(RANDOM, SECTION_CHAR))))
|
||||
.executes(c -> changeOffline(c, RandomUtilities.randomString(RANDOM, PREMIUM_CHARS, RANDOM.nextInt(3, 16)))))
|
||||
.then(literal("empty")
|
||||
.executes(c -> changeOffline(c, "")))
|
||||
);
|
||||
}
|
||||
|
||||
private static Session offline (final String username) {
|
||||
// This is how Minecraft's Main class does it
|
||||
return new Session(username, Uuids.getOfflinePlayerUuid(username),
|
||||
"", Optional.empty(), Optional.empty(), Session.AccountType.LEGACY);
|
||||
}
|
||||
|
||||
// TODO: Put this in a separate class
|
||||
private static void reconnect (final MinecraftClient client) {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
if (networkHandler == null) return; // single-player?
|
||||
|
||||
final ServerInfo info = networkHandler.getServerInfo();
|
||||
if (info == null) return; // definitely single-player
|
||||
|
||||
final ClientConnection connection = networkHandler.getConnection();
|
||||
final Screen screen = Objects.requireNonNullElseGet(
|
||||
((ClientCommonNetworkHandlerAccessor) networkHandler).getPostDisconnectScreen(),
|
||||
TitleScreen::new);
|
||||
|
||||
// This stuff needs to run after we close chat, otherwise it kicks us to the title screen. Don't ask me why
|
||||
client.send(() -> {
|
||||
connection.disconnect(Text.translatable("disconnect.transfer"));
|
||||
connection.tryDisableAutoRead();
|
||||
connection.handleDisconnection();
|
||||
|
||||
ConnectScreen.connect(screen, client, ServerAddress.parse(info.address), info, false, null);
|
||||
});
|
||||
}
|
||||
|
||||
private static int changeSession (final CommandContext<FabricClientCommandSource> context, final Session session) {
|
||||
final MinecraftClient client = context.getSource().getClient();
|
||||
((MinecraftClientAccessor) client).session(session);
|
||||
|
||||
reconnect(client);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private static int changeOffline (final CommandContext<FabricClientCommandSource> context, final String username) throws CommandSyntaxException {
|
||||
if (username.length() > 16) throw USERNAME_TOO_LONG.create();
|
||||
return changeSession(context, offline(username));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,27 @@
|
|||
package land.chipmunk.chipmunkmod.commands;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
import static land.chipmunk.chipmunkmod.util.BotValidationUtilities.*;
|
||||
|
||||
public class ValidateCommand {
|
||||
public static void register (CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("validate")
|
||||
.then(literal("hbot").then(argument("command", greedyString()).executes(c -> hbot(getString(c, "command")))))
|
||||
.then(literal("ubot").then(argument("command", greedyString()).executes(c -> ubot(getString(c, "command")))))
|
||||
.then(literal("ubotdev").then(argument("command", greedyString()).executes(c -> ubotdev(getString(c, "command")))))
|
||||
.then(literal("sbot").then(argument("command", greedyString()).executes(c -> sbot(getString(c, "command")))))
|
||||
// .then(literal("chipmunk").then(argument("command", greedyString()).executes(c -> chipmunk(getString(c, "command")))))
|
||||
.then(literal("chomens").then(argument("command", greedyString()).executes(c -> {
|
||||
c.getSource().sendFeedback(Text.literal("Warning: Manual ChomeNS Bot validation is deprecated. Please use the completions from typing the bot's prefix."));
|
||||
|
||||
return chomens(getString(c, "command"));
|
||||
})))
|
||||
.then(literal("fnfboyfriend").then(argument("command", greedyString()).executes(c -> fnfboyfriend(getString(c, "command")))))
|
||||
.then(literal("nbot").then(argument("command", greedyString()).executes(c -> nbot(getString(c, "command")))))
|
||||
.then(literal("kittycorp").then(argument("command", greedyString()).executes(c -> kittycorp(getString(c, "command")))))
|
||||
);
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.commands;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.argument;
|
||||
import static land.chipmunk.chipmunkmod.command.CommandManager.literal;
|
||||
import static land.chipmunk.chipmunkmod.util.BotValidationUtilities.*;
|
||||
|
||||
public class ValidateCommand {
|
||||
public static void register (final CommandDispatcher<FabricClientCommandSource> dispatcher) {
|
||||
dispatcher.register(
|
||||
literal("validate")
|
||||
.then(literal("hbot").then(argument("command", greedyString()).executes(c -> hbot(getString(c, "command")))))
|
||||
.then(literal("ubot").then(argument("command", greedyString()).executes(c -> ubot(getString(c, "command")))))
|
||||
.then(literal("ubotdev").then(argument("command", greedyString()).executes(c -> ubotdev(getString(c, "command")))))
|
||||
|
||||
.then(literal("sbot").then(argument("command", greedyString()).executes(c -> sbot(getString(c, "command")))))
|
||||
// .then(literal("chipmunk").then(argument("command", greedyString()).executes(c -> chipmunk(getString(c, "command")))))
|
||||
.then(literal("chomens").then(argument("command", greedyString()).executes(c -> chomens(getString(c, "command")))))
|
||||
.then(literal("nbot").then(argument("command", greedyString()).executes(c -> nbot(getString(c, "command")))))
|
||||
.then(literal("kittycorp").then(argument("command", greedyString()).executes(c -> kittycorp(getString(c, "command")))))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package land.chipmunk.chipmunkmod.config;
|
||||
|
||||
import land.chipmunk.chipmunkmod.config.migration.AbstractMigrationManager;
|
||||
import land.chipmunk.chipmunkmod.config.migrations.MigrationV0;
|
||||
import land.chipmunk.chipmunkmod.config.migrations.MigrationV1;
|
||||
import land.chipmunk.chipmunkmod.config.migrations.MigrationV2;
|
||||
import land.chipmunk.chipmunkmod.config.migrations.MigrationV3;
|
||||
|
||||
public final class ChipmunkModMigrations extends AbstractMigrationManager {
|
||||
public ChipmunkModMigrations () {
|
||||
super("version");
|
||||
|
||||
this.register(new MigrationV0()); // unversioned -> v0
|
||||
this.register(new MigrationV1());
|
||||
this.register(new MigrationV2());
|
||||
this.register(new MigrationV3());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package land.chipmunk.chipmunkmod.config;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minecraft.util.math.BlockBox;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||
|
||||
@ConfigSerializable
|
||||
public class Configuration {
|
||||
public CommandManager commands = new CommandManager();
|
||||
public CommandCore core = new CommandCore();
|
||||
public Bots bots = new Bots();
|
||||
public CustomChat customChat = new CustomChat();
|
||||
public SelfCare selfCare = new SelfCare();
|
||||
public String autoSkinUsername = "off";
|
||||
|
||||
@ConfigSerializable
|
||||
public static class CommandManager {
|
||||
public String prefix = ".";
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
public static class CommandCore {
|
||||
public BlockBox relativeArea = BlockBox.create(new BlockPos(0, 0, 0), new BlockPos(15, 0, 15));
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
public static class Bots {
|
||||
public BotInfo hbot = new BotInfo("#", null);
|
||||
public BotInfo sbot = new BotInfo(":", null);
|
||||
public BotInfo ubot = new BotInfo("\"", null);
|
||||
public BotInfo ubotdev = new BotInfo("d\"", null);
|
||||
public BotInfo chipmunk = new BotInfo("'", null);
|
||||
public BotInfo chomens = new BotInfo("*", null);
|
||||
public BotInfo nbot = new BotInfo("?", null);
|
||||
public BotInfo kittycorp = new BotInfo("^", null);
|
||||
public TestBotInfo testbot = new TestBotInfo("-", null);
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
public static class TestBotInfo {
|
||||
public String prefix;
|
||||
public @Nullable String webhookUrl;
|
||||
|
||||
public TestBotInfo () {
|
||||
}
|
||||
|
||||
public TestBotInfo (final String prefix, @Nullable final String webhookUrl) {
|
||||
this.prefix = prefix;
|
||||
this.webhookUrl = webhookUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
public static class BotInfo {
|
||||
public String prefix;
|
||||
public @Nullable String key;
|
||||
|
||||
public BotInfo () {
|
||||
}
|
||||
|
||||
public BotInfo (final String prefix, @Nullable final String key) {
|
||||
this.prefix = prefix;
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
public static class SelfCare {
|
||||
public boolean cspy = true;
|
||||
public boolean gameMode = true;
|
||||
public boolean op = true;
|
||||
}
|
||||
|
||||
@ConfigSerializable
|
||||
public static class CustomChat {
|
||||
public @NotNull Component format = // From amyavi
|
||||
Component.translatable("[%s] %s › %s", TextColor.fromHexString("#ff99dd"),
|
||||
Component.text("ChipmunkMod", TextColor.fromHexString("#ffccee"))
|
||||
.hoverEvent(HoverEvent.showText(
|
||||
Component.text("Click here to open the ChipmunkMod source code (7cc5c4f330d47060's fork)",
|
||||
NamedTextColor.WHITE)))
|
||||
.clickEvent(ClickEvent.openUrl("https://code.chipmunk.land/7cc5c4f330d47060/chipmunkmod")),
|
||||
Component.selector("@s").color(TextColor.fromHexString("#ffccee")),
|
||||
Component.text("MESSAGE", NamedTextColor.WHITE)
|
||||
.hoverEvent(HoverEvent.showText(
|
||||
Component.text("Click here to copy the message",
|
||||
NamedTextColor.WHITE)))
|
||||
.clickEvent(ClickEvent.copyToClipboard("MESSAGE"))
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package land.chipmunk.chipmunkmod.config;
|
||||
|
||||
import land.chipmunk.chipmunkmod.config.migration.AbstractMigrationManager;
|
||||
import land.chipmunk.chipmunkmod.config.migrations.MigrationName3V0;
|
||||
import land.chipmunk.chipmunkmod.config.migrations.MigrationName3V1;
|
||||
import land.chipmunk.chipmunkmod.config.migrations.MigrationName3V2;
|
||||
|
||||
public final class Name3ModMigrations extends AbstractMigrationManager {
|
||||
public Name3ModMigrations() {
|
||||
super("version_name3");
|
||||
|
||||
this.register(new MigrationName3V0()); // unversioned -> v0
|
||||
this.register(new MigrationName3V1());
|
||||
this.register(new MigrationName3V2());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package land.chipmunk.chipmunkmod.config.migration;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
// Makes it easier for forks to add their own config versioning structure
|
||||
public abstract class AbstractMigrationManager {
|
||||
private final List<ConfigMigration> migrations = new ArrayList<>();
|
||||
private final Object[] versionKey;
|
||||
|
||||
public AbstractMigrationManager (final Object... versionKey) {
|
||||
this.versionKey = versionKey;
|
||||
}
|
||||
|
||||
protected void register (final ConfigMigration migration) {
|
||||
this.migrations.add(migration);
|
||||
}
|
||||
|
||||
protected void registerFrom (final int version, final Supplier<ConfigurationTransformation> supplier) {
|
||||
this.migrations.add(ConfigMigration.from(version, supplier));
|
||||
}
|
||||
|
||||
public ConfigurationTransformation.Versioned create () {
|
||||
final ConfigurationTransformation.VersionedBuilder builder = ConfigurationTransformation.versionedBuilder()
|
||||
.versionKey(versionKey);
|
||||
|
||||
this.migrations.forEach(migration -> builder.addVersion(migration.version(), migration.create()));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public <N extends ConfigurationNode> void setLatest (final N config) throws ConfigurateException {
|
||||
final ConfigurationTransformation.Versioned transforms = this.create();
|
||||
config.node(transforms.versionKey()).set(Integer.class, transforms.latestVersion());
|
||||
}
|
||||
|
||||
public <N extends ConfigurationNode> boolean migrate (final N config) throws ConfigurateException {
|
||||
final ConfigurationTransformation.Versioned transforms = this.create();
|
||||
final int version = transforms.version(config);
|
||||
|
||||
if (version > transforms.latestVersion()) {
|
||||
ChipmunkMod.LOGGER.warn("Latest config version is {}, but yours is {}! Are you from the future?",
|
||||
transforms.latestVersion(), version);
|
||||
return false;
|
||||
}
|
||||
|
||||
transforms.apply(config);
|
||||
|
||||
final int newVersion = transforms.version(config);
|
||||
if (version != newVersion) {
|
||||
ChipmunkMod.LOGGER.info("Migrated config from version {} to {}!", version, newVersion);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package land.chipmunk.chipmunkmod.config.migration;
|
||||
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface ConfigMigration {
|
||||
static ConfigMigration from (final int version, final Supplier<ConfigurationTransformation> supplier) {
|
||||
return new ConfigMigrationImpl(version, supplier);
|
||||
}
|
||||
|
||||
int version ();
|
||||
|
||||
ConfigurationTransformation create ();
|
||||
|
||||
record ConfigMigrationImpl(int version, Supplier<ConfigurationTransformation> supplier) implements ConfigMigration {
|
||||
@Override
|
||||
public ConfigurationTransformation create () {
|
||||
return this.supplier.get();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package land.chipmunk.chipmunkmod.config.migrations;
|
||||
|
||||
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import static org.spongepowered.configurate.NodePath.path;
|
||||
|
||||
public final class MigrationName3V0 implements ConfigMigration {
|
||||
@Override
|
||||
public int version() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationTransformation create() {
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(path("testbotWebhook"), TransformAction.remove())
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package land.chipmunk.chipmunkmod.config.migrations;
|
||||
|
||||
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import static org.spongepowered.configurate.NodePath.path;
|
||||
|
||||
public final class MigrationName3V1 implements ConfigMigration {
|
||||
@Override
|
||||
public int version() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationTransformation create() {
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(path("bots", "fnfboyfriend"), TransformAction.remove())
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package land.chipmunk.chipmunkmod.config.migrations;
|
||||
|
||||
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import static org.spongepowered.configurate.NodePath.path;
|
||||
|
||||
public final class MigrationName3V2 implements ConfigMigration {
|
||||
@Override
|
||||
public int version() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationTransformation create() {
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(path("bots", "qilk"), TransformAction.remove())
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package land.chipmunk.chipmunkmod.config.migrations;
|
||||
|
||||
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import static org.spongepowered.configurate.NodePath.path;
|
||||
|
||||
public final class MigrationV0 implements ConfigMigration {
|
||||
@Override
|
||||
public int version () {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationTransformation create () {
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(path("fullbright"), TransformAction.remove())
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package land.chipmunk.chipmunkmod.config.migrations;
|
||||
|
||||
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
|
||||
import land.chipmunk.chipmunkmod.util.configurate.ConfigurateUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.SelectorComponent;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.renderer.TranslatableComponentRenderer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.spongepowered.configurate.NodePath.path;
|
||||
|
||||
public final class MigrationV1 implements ConfigMigration {
|
||||
@Override
|
||||
public int version () {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationTransformation create () {
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(path("customChat", "format"),
|
||||
ConfigurateUtilities.componentTransformer(new CustomChatFormatMigrator(), null))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static final class CustomChatFormatMigrator extends TranslatableComponentRenderer<Void> {
|
||||
@Override
|
||||
protected @NotNull Component renderSelector (final @NotNull SelectorComponent component,
|
||||
final @NotNull Void context) {
|
||||
final String pattern = component.pattern();
|
||||
if (pattern.equals("USERNAME") || pattern.equals("UUID")) {
|
||||
final SelectorComponent.Builder builder = Component.selector()
|
||||
.pattern("@s");
|
||||
|
||||
return this.mergeStyleAndOptionallyDeepRender(component, builder, context);
|
||||
}
|
||||
|
||||
return super.renderSelector(component, context);
|
||||
}
|
||||
|
||||
// Older configs had things like: `{ "text": "", "extra": ["MESSAGE"] }`
|
||||
// We don't need that anymore, transform it to `{ "text": "MESSAGE" }`
|
||||
@Override
|
||||
protected @NotNull Component renderText (@NotNull final TextComponent component, @NotNull final Void context) {
|
||||
if (!component.content().isEmpty() || component.children().size() != 1) {
|
||||
return super.renderText(component, context);
|
||||
}
|
||||
|
||||
final Component onlyChild = component.children().getFirst();
|
||||
if (!onlyChild.equals(Component.text("MESSAGE"))) {
|
||||
return super.renderText(component, context);
|
||||
}
|
||||
|
||||
final Component newComponent = component
|
||||
.children(List.of()); // Clear children
|
||||
final TextComponent.Builder builder = Component.text()
|
||||
.content("MESSAGE");
|
||||
|
||||
return this.mergeStyleAndOptionallyDeepRender(newComponent, builder, context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package land.chipmunk.chipmunkmod.config.migrations;
|
||||
|
||||
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import static org.spongepowered.configurate.NodePath.path;
|
||||
|
||||
public class MigrationV2 implements ConfigMigration {
|
||||
@Override
|
||||
public int version () {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationTransformation create () {
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(path("bots", "chomens", "authKey"), TransformAction.remove())
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package land.chipmunk.chipmunkmod.config.migrations;
|
||||
|
||||
import land.chipmunk.chipmunkmod.config.migration.ConfigMigration;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import static org.spongepowered.configurate.NodePath.path;
|
||||
|
||||
public class MigrationV3 implements ConfigMigration {
|
||||
@Override
|
||||
public int version () {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationTransformation create () {
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(path("bots", "chomens", "formatKey"), TransformAction.remove())
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.data;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
// ? Am I reinventing the wheel here?
|
||||
public class BlockArea {
|
||||
public BlockPos start;
|
||||
public BlockPos end;
|
||||
|
||||
public BlockArea (BlockPos start, BlockPos end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
}
|
|
@ -1,25 +1,56 @@
|
|||
package land.chipmunk.chipmunkmod.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.util.TextUtilities;
|
||||
import net.minecraft.text.Text;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ChomeNSBotCommand {
|
||||
public final String name;
|
||||
public final TrustLevel trustLevel;
|
||||
public final List<String> aliases = new ArrayList<>();
|
||||
public record ChomeNSBotCommand(String name, TrustLevel trustLevel, List<String> aliases) {
|
||||
public static @Nullable ChomeNSBotCommand fromText (final Text component) {
|
||||
final String name = TextUtilities.plainOrNull(component);
|
||||
if (name == null) return null;
|
||||
|
||||
public ChomeNSBotCommand (
|
||||
String name,
|
||||
TrustLevel trustLevel
|
||||
) {
|
||||
this.name = name;
|
||||
this.trustLevel = trustLevel;
|
||||
final List<Text> children = component.getSiblings();
|
||||
if (children.size() < 2) return null; // must have at least trust level and alias boolean
|
||||
|
||||
final TrustLevel trustLevel = TrustLevel.fromText(children.getFirst());
|
||||
if (trustLevel == null) return null;
|
||||
|
||||
final String hasAliasesString = TextUtilities.plainOrNull(children.get(1));
|
||||
if (hasAliasesString == null) return null;
|
||||
|
||||
final boolean hasAliases = Boolean.parseBoolean(hasAliasesString);
|
||||
if (!hasAliases) return new ChomeNSBotCommand(
|
||||
ChipmunkMod.CONFIG.bots.chomens.prefix + name, trustLevel, List.of());
|
||||
|
||||
final List<String> aliases = children.stream()
|
||||
.skip(2)
|
||||
.map(TextUtilities::plainOrNull)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
return new ChomeNSBotCommand(
|
||||
ChipmunkMod.CONFIG.bots.chomens.prefix + name, trustLevel, aliases);
|
||||
}
|
||||
|
||||
public enum TrustLevel {
|
||||
PUBLIC,
|
||||
TRUSTED,
|
||||
ADMIN,
|
||||
OWNER
|
||||
OWNER;
|
||||
|
||||
public static TrustLevel fromText (final Text component) {
|
||||
final String trustLevelString = TextUtilities.plainOrNull(component);
|
||||
if (trustLevelString == null) return null;
|
||||
|
||||
try {
|
||||
return TrustLevel.valueOf(trustLevelString);
|
||||
} catch (final IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,14 +11,14 @@ public class MutablePlayerListEntry {
|
|||
public int latency;
|
||||
public Text displayName;
|
||||
|
||||
public MutablePlayerListEntry(GameProfile profile, GameMode gamemode, int latency, Text displayName) {
|
||||
public MutablePlayerListEntry (final GameProfile profile, final GameMode gamemode, final int latency, final Text displayName) {
|
||||
this.profile = profile;
|
||||
this.gamemode = gamemode;
|
||||
this.latency = latency;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public MutablePlayerListEntry (PlayerListS2CPacket.Entry entry) {
|
||||
public MutablePlayerListEntry (final PlayerListS2CPacket.Entry entry) {
|
||||
this(entry.profile(), entry.gameMode(), entry.latency(), entry.displayName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,20 @@ package land.chipmunk.chipmunkmod.listeners;
|
|||
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class Listener {
|
||||
public void chatMessageReceived (Text message) {}
|
||||
public interface Listener {
|
||||
default void packetReceived (final Packet<?> packet) { }
|
||||
|
||||
public void packetReceived (Packet<?> packet) {}
|
||||
default void packetSent (final Packet<?> packet) { }
|
||||
|
||||
public void packetSent (Packet<?> packet) {}
|
||||
default void chatMessageReceived (final Text message) { }
|
||||
|
||||
public void coreReady () {}
|
||||
default void overlayMessageReceived (final Text message) { }
|
||||
|
||||
public void coreMoved () {}
|
||||
default void coreReady () { }
|
||||
|
||||
default void coreMoved () { }
|
||||
|
||||
default void positionChanged (final Vec3d newPosition) { }
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.util.List;
|
|||
public class ListenerManager {
|
||||
public static List<Listener> listeners = new ArrayList<>();
|
||||
|
||||
public static void addListener (Listener listener) {
|
||||
public static void addListener (final Listener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import land.chipmunk.chipmunkmod.modules.RainbowName;
|
||||
import land.chipmunk.chipmunkmod.util.Debug;
|
||||
import land.chipmunk.chipmunkmod.util.Executor;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.hud.ChatHudLine;
|
||||
import net.minecraft.client.gui.hud.MessageIndicator;
|
||||
import net.minecraft.network.message.MessageSignatureData;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableTextContent;
|
||||
import net.minecraft.util.Nullables;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(net.minecraft.client.gui.hud.ChatHud.class)
|
||||
public abstract class ChatHudMixin {
|
||||
|
||||
@Shadow
|
||||
public abstract void addMessage(Text message, @Nullable MessageSignatureData signature, @Nullable MessageIndicator indicator);
|
||||
|
||||
@Shadow @Final private MinecraftClient client;
|
||||
@Shadow @Final private static Logger LOGGER;
|
||||
|
||||
@Shadow protected abstract void logChatMessage(ChatHudLine message);
|
||||
@Shadow protected abstract void addVisibleMessage(ChatHudLine message);
|
||||
@Shadow protected abstract void addMessage(ChatHudLine message);
|
||||
|
||||
|
||||
@Unique
|
||||
private void customLogChatMessage(ChatHudLine message) {
|
||||
String string = message.content().getString().replaceAll("\r", "\\\\r").replaceAll("\n", "\\\\n");
|
||||
String string2 = Nullables.map(message.indicator(), MessageIndicator::loggedName);
|
||||
if (string2 != null) {
|
||||
LOGGER.info("[{}] [CHAT] {}", string2, string);
|
||||
} else {
|
||||
LOGGER.info("[CHAT] {}", string);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;Lnet/minecraft/client/gui/hud/MessageIndicator;)V", cancellable = true)
|
||||
public void chipmunkmod$generalAddMessageMixin(Text message, MessageSignatureData signatureData, MessageIndicator indicator, CallbackInfo ci) {
|
||||
ChatHudLine chatHudLine = new ChatHudLine(this.client.inGameHud.getTicks(), message, signatureData, indicator);
|
||||
try {
|
||||
if (RainbowName.INSTANCE.enabled) {
|
||||
if (message.getString().contains("Your nickname is now ") || message.getString().contains("Nickname changed.")) {
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (((TranslatableTextContent) message.getContent()).getKey().equals("advMode.setCommand.success")) {
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
} catch (ClassCastException ignored) {}
|
||||
|
||||
for (Listener listener : ListenerManager.listeners) {
|
||||
listener.chatMessageReceived(message);
|
||||
}
|
||||
|
||||
customLogChatMessage(chatHudLine);
|
||||
addVisibleMessage(chatHudLine);
|
||||
addMessage(chatHudLine);
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,98 +1,101 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.command.CommandManager;
|
||||
import land.chipmunk.chipmunkmod.modules.ChomeNSBotCommandSuggestions;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Mixin(net.minecraft.client.gui.screen.ChatInputSuggestor.class)
|
||||
public class ChatInputSuggestorMixin {
|
||||
@Shadow
|
||||
private CompletableFuture<Suggestions> pendingSuggestions;
|
||||
|
||||
@Shadow
|
||||
public void show (boolean narrateFirstSuggestion) {}
|
||||
|
||||
@Shadow
|
||||
private static int getStartOfCurrentWord (String input) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Mutable
|
||||
@Final
|
||||
@Shadow
|
||||
final TextFieldWidget textField;
|
||||
|
||||
public ChatInputSuggestorMixin () {
|
||||
textField = null;
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "refresh()V")
|
||||
public void refresh (CallbackInfo ci) {
|
||||
final CommandManager commandManager = CommandManager.INSTANCE;
|
||||
|
||||
final String text = this.textField.getText();
|
||||
final int cursor = this.textField.getCursor();
|
||||
|
||||
final ClientPlayerEntity player = MinecraftClient.getInstance().player;
|
||||
|
||||
final String chomeNSPrefix = ChipmunkMod.CONFIG.bots.chomens.prefix;
|
||||
|
||||
if (!text.contains(" ") && text.startsWith(chomeNSPrefix) && player != null) {
|
||||
final String textUpToCursor = text.substring(0, cursor);
|
||||
|
||||
final List<String> commands = ChomeNSBotCommandSuggestions.INSTANCE.commands
|
||||
.stream()
|
||||
.map((command) -> command.name)
|
||||
.toList();
|
||||
|
||||
pendingSuggestions = CommandSource.suggestMatching(
|
||||
commands,
|
||||
new SuggestionsBuilder(
|
||||
textUpToCursor,
|
||||
getStartOfCurrentWord(textUpToCursor)
|
||||
)
|
||||
);
|
||||
|
||||
pendingSuggestions.thenRun(() -> {
|
||||
if (!pendingSuggestions.isDone()) return;
|
||||
|
||||
show(true);
|
||||
});
|
||||
} else if (cursor >= commandManager.prefix.length() && text.startsWith(commandManager.prefix)) {
|
||||
final StringReader reader = new StringReader(text);
|
||||
reader.setCursor(commandManager.prefix.length()); // Skip the prefix
|
||||
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null) return;
|
||||
|
||||
final CommandDispatcher<FabricClientCommandSource> dispatcher = commandManager.dispatcher;
|
||||
final FabricClientCommandSource commandSource = (FabricClientCommandSource) networkHandler.getCommandSource();
|
||||
|
||||
pendingSuggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(reader, commandSource), cursor);
|
||||
show(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.command.CommandManager;
|
||||
import land.chipmunk.chipmunkmod.data.ChomeNSBotCommand;
|
||||
import land.chipmunk.chipmunkmod.modules.ChomeNSBotCommandSuggestions;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Mixin(net.minecraft.client.gui.screen.ChatInputSuggestor.class)
|
||||
public class ChatInputSuggestorMixin {
|
||||
@Mutable
|
||||
@Final
|
||||
@Shadow
|
||||
final TextFieldWidget textField;
|
||||
@Shadow
|
||||
private CompletableFuture<Suggestions> pendingSuggestions;
|
||||
|
||||
public ChatInputSuggestorMixin () {
|
||||
textField = null;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private static int getStartOfCurrentWord (final String input) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public void show (final boolean narrateFirstSuggestion) {
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "refresh()V")
|
||||
public void refresh (final CallbackInfo ci) {
|
||||
final CommandManager commandManager = CommandManager.INSTANCE;
|
||||
|
||||
if (this.textField == null) return;
|
||||
|
||||
final String text = this.textField.getText();
|
||||
final int cursor = this.textField.getCursor();
|
||||
|
||||
final ClientPlayerEntity player = MinecraftClient.getInstance().player;
|
||||
|
||||
final String chomeNSPrefix = ChipmunkMod.CONFIG.bots.chomens.prefix;
|
||||
|
||||
if (!text.contains(" ") && text.startsWith(chomeNSPrefix) && player != null) {
|
||||
final String textUpToCursor = text.substring(0, cursor);
|
||||
|
||||
final List<String> commands = ChomeNSBotCommandSuggestions.INSTANCE.commands
|
||||
.stream()
|
||||
.map(ChomeNSBotCommand::name)
|
||||
.toList();
|
||||
|
||||
pendingSuggestions = CommandSource.suggestMatching(
|
||||
commands,
|
||||
new SuggestionsBuilder(
|
||||
textUpToCursor,
|
||||
getStartOfCurrentWord(textUpToCursor)
|
||||
)
|
||||
);
|
||||
|
||||
pendingSuggestions.thenRun(() -> {
|
||||
if (!pendingSuggestions.isDone()) return;
|
||||
|
||||
show(true);
|
||||
});
|
||||
} else if (cursor >= commandManager.prefix.length() && text.startsWith(commandManager.prefix)) {
|
||||
final StringReader reader = new StringReader(text);
|
||||
reader.setCursor(commandManager.prefix.length()); // Skip the prefix
|
||||
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null) return;
|
||||
|
||||
final CommandDispatcher<FabricClientCommandSource> dispatcher = commandManager.dispatcher;
|
||||
final FabricClientCommandSource commandSource = (FabricClientCommandSource) networkHandler.getCommandSource();
|
||||
|
||||
pendingSuggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(reader, commandSource), cursor);
|
||||
show(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,127 +1,116 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.data.ChomeNSBotCommand;
|
||||
import land.chipmunk.chipmunkmod.modules.ChomeNSBotCommandSuggestions;
|
||||
import land.chipmunk.chipmunkmod.util.BotValidationUtilities;
|
||||
import land.chipmunk.chipmunkmod.util.Executor;
|
||||
import land.chipmunk.chipmunkmod.util.Webhook;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.ChatInputSuggestor;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(value = net.minecraft.client.gui.screen.ChatScreen.class)
|
||||
public class ChatScreenMixin extends Screen {
|
||||
@Shadow protected TextFieldWidget chatField;
|
||||
@Shadow private String originalChatText;
|
||||
@Shadow ChatInputSuggestor chatInputSuggestor;
|
||||
@Shadow private int messageHistoryIndex = -1;
|
||||
|
||||
public ChatScreenMixin(String originalChatText) {
|
||||
super(Text.translatable("chat_screen.title"));
|
||||
this.originalChatText = originalChatText;
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "init", cancellable = true)
|
||||
public void init (CallbackInfo ci) {
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
this.messageHistoryIndex = client.inGameHud.getChatHud().getMessageHistory().size();
|
||||
this.chatField = new TextFieldWidget(client.advanceValidatingTextRenderer, 4, this.height - 12, this.width - 4, 12, Text.translatable("chat.editBox")) {
|
||||
protected MutableText getNarrationMessage() {
|
||||
return super.getNarrationMessage().append(ChatScreenMixin.this.chatInputSuggestor.getNarration());
|
||||
}
|
||||
};
|
||||
this.chatField.setMaxLength(Integer.MAX_VALUE);
|
||||
this.chatField.setDrawsBackground(false);
|
||||
this.chatField.setText(this.originalChatText);
|
||||
this.chatField.setChangedListener(this::onChatFieldUpdate);
|
||||
this.chatField.setFocusUnlocked(false);
|
||||
this.addSelectableChild(this.chatField);
|
||||
this.chatInputSuggestor = new ChatInputSuggestor(this.client, this, this.chatField, this.textRenderer, false, false, 1, 10, true, -805306368);
|
||||
this.chatInputSuggestor.refresh();
|
||||
this.setInitialFocus(this.chatField);
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "sendMessage", cancellable = true)
|
||||
public void sendMessage(String chatText, boolean addToHistory, CallbackInfo ci) {
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
if (addToHistory) {
|
||||
client.inGameHud.getChatHud().addToMessageHistory(chatText);
|
||||
}
|
||||
if(ChipmunkMod.CONFIG.bots.testbot.webhookUrl != null && chatText.startsWith("-")) {
|
||||
Executor.service.submit(() -> {
|
||||
try {
|
||||
Webhook.send(ChipmunkMod.CONFIG.bots.testbot.webhookUrl, client.getSession().getUsername());
|
||||
} catch (IOException e) {
|
||||
ChipmunkMod.LOGGER.error("fard webhook url !!!t");
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
} else if (chatText.startsWith(ChipmunkMod.CONFIG.bots.chomens.prefix)) {
|
||||
final List<ChomeNSBotCommand> commands = ChomeNSBotCommandSuggestions.INSTANCE.commands;
|
||||
|
||||
final List<String> moreOrTrustedCommands = commands.stream()
|
||||
.filter((command) -> command.trustLevel != ChomeNSBotCommand.TrustLevel.PUBLIC)
|
||||
.map((command) -> command.name.toLowerCase())
|
||||
.toList();
|
||||
|
||||
final List<String> aliases = new ArrayList<>();
|
||||
for (ChomeNSBotCommand command : commands) {
|
||||
if (command.trustLevel == ChomeNSBotCommand.TrustLevel.PUBLIC) continue;
|
||||
|
||||
aliases.addAll(command.aliases);
|
||||
}
|
||||
|
||||
final String chatCommand = chatText.toLowerCase().split("\\s")[0];
|
||||
|
||||
final int prefixLength = ChipmunkMod.CONFIG.bots.chomens.prefix.length();
|
||||
|
||||
if (
|
||||
moreOrTrustedCommands.contains(chatCommand) ||
|
||||
aliases.contains(chatCommand.substring(prefixLength))
|
||||
) {
|
||||
try {
|
||||
BotValidationUtilities.chomens(chatText.substring(prefixLength));
|
||||
|
||||
ci.cancel();
|
||||
|
||||
return;
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (client == null) return;
|
||||
|
||||
if (chatText.startsWith("/")) {
|
||||
client.player.networkHandler.sendChatCommand(chatText.substring(1));
|
||||
} else {
|
||||
client.player.networkHandler.sendChatMessage(chatText);
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void onChatFieldUpdate(String chatText) {
|
||||
String string = this.chatField.getText();
|
||||
this.chatInputSuggestor.setWindowActive(!string.equals(this.originalChatText));
|
||||
this.chatInputSuggestor.refresh();
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.data.ChomeNSBotCommand;
|
||||
import land.chipmunk.chipmunkmod.modules.ChomeNSBotCommandSuggestions;
|
||||
import land.chipmunk.chipmunkmod.util.BotValidationUtilities;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.ChatScreen;
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(value = ChatScreen.class)
|
||||
public abstract class ChatScreenMixin {
|
||||
@Shadow
|
||||
protected TextFieldWidget chatField;
|
||||
|
||||
// infinite chat
|
||||
// can't use ModifyConstant due to VFP, see:
|
||||
// https://github.com/ViaVersion/ViaFabricPlus/blob/main/src/main/java/com/viaversion/viafabricplus/injection/mixin/features/limitation/max_chat_length/MixinChatScreen.java
|
||||
@Inject(method = "init", at = @At("RETURN"))
|
||||
private void init (final CallbackInfo ci) {
|
||||
chatField.setMaxLength(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Inject(method = "sendMessage", at = @At("HEAD"), cancellable = true)
|
||||
private void sendMessage (final String chatText, final boolean addToHistory, final CallbackInfo ci) {
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
if (addToHistory) {
|
||||
client.inGameHud.getChatHud().addToMessageHistory(chatText);
|
||||
}
|
||||
|
||||
if (ChipmunkMod.CONFIG.bots.testbot.webhookUrl != null && chatText.startsWith(ChipmunkMod.CONFIG.bots.testbot.prefix)) {
|
||||
ChipmunkMod.executorService.submit(() -> {
|
||||
try {
|
||||
final URL url = new URI(ChipmunkMod.CONFIG.bots.testbot.webhookUrl).toURL();
|
||||
|
||||
final HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
||||
connection.addRequestProperty("Content-Type", "application/json");
|
||||
connection.addRequestProperty("User-Agent", "ChipmunkMod");
|
||||
connection.setDoOutput(true);
|
||||
connection.setRequestMethod("POST");
|
||||
|
||||
final JsonObject jsonObject = new JsonObject();
|
||||
|
||||
jsonObject.addProperty("username", "ChipmunkMod UwU");
|
||||
jsonObject.addProperty("content", MinecraftClient.getInstance().getSession().getUsername());
|
||||
|
||||
final OutputStream stream = connection.getOutputStream();
|
||||
stream.write(jsonObject.toString().getBytes());
|
||||
stream.flush();
|
||||
stream.close();
|
||||
|
||||
connection.getInputStream().close();
|
||||
connection.disconnect();
|
||||
} catch (final IOException | URISyntaxException e) {
|
||||
ChipmunkMod.LOGGER.error("Error while trying to request TestBot webhook", e);
|
||||
}
|
||||
});
|
||||
} else if (chatText.startsWith(ChipmunkMod.CONFIG.bots.chomens.prefix)) {
|
||||
final List<ChomeNSBotCommand> commands = ChomeNSBotCommandSuggestions.INSTANCE.commands;
|
||||
|
||||
final List<String> moreOrTrustedCommands = commands.stream()
|
||||
.filter(command -> command.trustLevel() != ChomeNSBotCommand.TrustLevel.PUBLIC)
|
||||
.map(command -> command.name().toLowerCase())
|
||||
.toList();
|
||||
|
||||
final List<String> aliases = new ArrayList<>();
|
||||
for (final ChomeNSBotCommand command : commands) {
|
||||
if (command.trustLevel() == ChomeNSBotCommand.TrustLevel.PUBLIC) continue;
|
||||
|
||||
aliases.addAll(command.aliases());
|
||||
}
|
||||
|
||||
final String chatCommand = chatText.toLowerCase().split("\\s")[0];
|
||||
|
||||
final int prefixLength = ChipmunkMod.CONFIG.bots.chomens.prefix.length();
|
||||
|
||||
if (
|
||||
moreOrTrustedCommands.contains(chatCommand) ||
|
||||
aliases.contains(chatCommand.substring(prefixLength))
|
||||
) {
|
||||
try {
|
||||
BotValidationUtilities.chomens(chatText.substring(prefixLength));
|
||||
ci.cancel();
|
||||
return;
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (client.player == null) return;
|
||||
|
||||
if (chatText.startsWith("/")) {
|
||||
client.player.networkHandler.sendChatCommand(chatText.substring(1));
|
||||
} else {
|
||||
client.player.networkHandler.sendChatMessage(chatText);
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.network.ClientCommonNetworkHandler;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ClientCommonNetworkHandler.class)
|
||||
public interface ClientCommonNetworkHandlerAccessor {
|
||||
@Accessor("postDisconnectScreen")
|
||||
Screen getPostDisconnectScreen ();
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.listener.PacketListener;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ClientConnection.class)
|
||||
public interface ClientConnectionAccessor {
|
||||
@Accessor("packetListener")
|
||||
PacketListener packetListener ();
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.listener.PacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(ClientConnection.class)
|
||||
public interface ClientConnectionInvoker {
|
||||
@Invoker("handlePacket")
|
||||
static <T extends PacketListener> void handlePacket (Packet<T> packet, PacketListener listener) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
|
@ -1,99 +1,133 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import land.chipmunk.chipmunkmod.util.Chat;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.network.listener.PacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Mixin(net.minecraft.network.ClientConnection.class)
|
||||
public class ClientConnectionMixin {
|
||||
@Unique
|
||||
private static final Pattern CUSTOM_PITCH_PATTERN = Pattern.compile(".*\\.pitch\\.(.*)");
|
||||
|
||||
@Inject(method = "exceptionCaught", at = @At("HEAD"), cancellable = true)
|
||||
private void exceptionCaught (ChannelHandlerContext context, Throwable ex, CallbackInfo ci) {
|
||||
Chat.sendGold("ChipmunkMod caught an exception in ClientConnection.");
|
||||
ci.cancel();
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
@Inject(method = "handlePacket", at = @At("HEAD"), cancellable = true)
|
||||
private static void handlePacket (Packet<?> packet, PacketListener _listener, CallbackInfo ci) {
|
||||
for (Listener listener : ListenerManager.listeners) {
|
||||
listener.packetReceived(packet);
|
||||
}
|
||||
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
// please don't skid this.,.
|
||||
// mabe mabe mabe
|
||||
// lol i had my own im just gonna cop ypaste that :D
|
||||
if(packet instanceof ParticleS2CPacket) {
|
||||
if(((ParticleS2CPacket) packet).getCount()>1000) {
|
||||
if(((ParticleS2CPacket) packet).getCount()>1000) Chat.sendGold("ChipmunkMod prevented a particle kick!");
|
||||
ci.cancel();
|
||||
}
|
||||
} else if (packet instanceof PlaySoundS2CPacket t_packet) {
|
||||
final SoundEvent soundEvent = t_packet.getSound().value();
|
||||
|
||||
final Identifier sound = soundEvent.id();
|
||||
|
||||
final Matcher matcher = CUSTOM_PITCH_PATTERN.matcher(sound.getPath());
|
||||
|
||||
if (!matcher.find()) return;
|
||||
|
||||
try {
|
||||
final String stringPitch = matcher.group(1);
|
||||
|
||||
final float pitch = Float.parseFloat(stringPitch);
|
||||
|
||||
final ClientWorld world = client.world;
|
||||
|
||||
if (world == null) return;
|
||||
|
||||
// huge mess
|
||||
final SoundEvent newSound = SoundEvent.of(Identifier.of(sound.getNamespace(), sound.getPath().substring(0, sound.getPath().length() - (".pitch." + stringPitch).length())));
|
||||
|
||||
client.executeSync(() -> world.playSound(client.player, t_packet.getX(), t_packet.getY(), t_packet.getZ(), newSound, t_packet.getCategory(), t_packet.getVolume(), pitch, t_packet.getSeed()));
|
||||
|
||||
ci.cancel();
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (t_packet.getVolume() == 1 && sound.getPath().equals("entity.enderman.scream")) ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "send(Lnet/minecraft/network/packet/Packet;)V", cancellable = true)
|
||||
private void sendPacket (Packet<?> packet, CallbackInfo ci) {
|
||||
if (packet instanceof RequestCommandCompletionsC2SPacket t_packet) {
|
||||
if (t_packet.getPartialCommand().length() > 2048) { // why was this comment here
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (Listener listener : ListenerManager.listeners) {
|
||||
listener.packetSent(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import land.chipmunk.chipmunkmod.util.Chat;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.network.PacketCallbacks;
|
||||
import net.minecraft.network.listener.PacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Mixin(net.minecraft.network.ClientConnection.class)
|
||||
public class ClientConnectionMixin {
|
||||
@Unique
|
||||
private static final double MAX_PARTICLES_PER_PACKET = 1000;
|
||||
@Unique
|
||||
private static final Pattern CUSTOM_PITCH_PATTERN = Pattern.compile(".*\\.pitch\\.(.*)");
|
||||
|
||||
@Inject(method = "exceptionCaught", at = @At("HEAD"), cancellable = true)
|
||||
private void exceptionCaught(ChannelHandlerContext context, Throwable ex, CallbackInfo ci) {
|
||||
Chat.sendGold("ChipmunkMod caught an exception in ClientConnection.");
|
||||
ci.cancel();
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
@Inject(method = "handlePacket", at = @At("HEAD"), cancellable = true)
|
||||
private static <T extends PacketListener> void handlePacket (
|
||||
final Packet<T> packet,
|
||||
final PacketListener packetListener,
|
||||
final CallbackInfo ci
|
||||
) {
|
||||
for (final Listener listener : ListenerManager.listeners) {
|
||||
listener.packetReceived(packet);
|
||||
}
|
||||
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
// this check is very easy to bypass in 2025
|
||||
if (
|
||||
packet instanceof final ParticleS2CPacket t_packet
|
||||
&& t_packet.getCount() > MAX_PARTICLES_PER_PACKET
|
||||
) {
|
||||
ci.cancel();
|
||||
Chat.sendGold("ChipmunkMod prevented a particle kick!");
|
||||
} else if (packet instanceof final PlaySoundS2CPacket t_packet) {
|
||||
final SoundEvent soundEvent = t_packet.getSound().value();
|
||||
|
||||
final Identifier sound = soundEvent.id();
|
||||
|
||||
final Matcher matcher = CUSTOM_PITCH_PATTERN.matcher(sound.getPath());
|
||||
|
||||
if (!matcher.find()) return;
|
||||
|
||||
try {
|
||||
final String stringPitch = matcher.group(1);
|
||||
|
||||
final float pitch = Float.parseFloat(stringPitch);
|
||||
|
||||
final ClientWorld world = client.world;
|
||||
|
||||
if (world == null) return;
|
||||
|
||||
final SoundEvent newSound = SoundEvent.of(
|
||||
Identifier.of(
|
||||
sound.getNamespace(),
|
||||
sound.getPath().substring(0, sound.getPath().length() - (".pitch." + stringPitch).length())
|
||||
)
|
||||
);
|
||||
|
||||
client.execute(() -> world.playSound(
|
||||
client.player,
|
||||
|
||||
t_packet.getX(),
|
||||
t_packet.getY(),
|
||||
t_packet.getZ(),
|
||||
|
||||
newSound,
|
||||
t_packet.getCategory(),
|
||||
|
||||
t_packet.getVolume(),
|
||||
pitch,
|
||||
|
||||
t_packet.getSeed()
|
||||
));
|
||||
|
||||
ci.cancel();
|
||||
return;
|
||||
} catch (final NumberFormatException e) {
|
||||
ChipmunkMod.LOGGER.error("Failed to parse custom pitch", e);
|
||||
}
|
||||
|
||||
if (t_packet.getVolume() == 1 && sound.getPath().equals("entity.enderman.scream")) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WrapMethod(method = "send(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/PacketCallbacks;Z)V")
|
||||
private void sendPacket (
|
||||
final Packet<?> packet,
|
||||
final PacketCallbacks callbacks,
|
||||
final boolean flush,
|
||||
final Operation<Void> original
|
||||
) {
|
||||
if (
|
||||
packet instanceof final RequestCommandCompletionsC2SPacket t_packet
|
||||
&& t_packet.getPartialCommand().length() > 2048
|
||||
) return;
|
||||
|
||||
for (final Listener listener : ListenerManager.listeners) {
|
||||
listener.packetSent(packet);
|
||||
}
|
||||
|
||||
original.call(packet, callbacks, flush);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.client.network.PlayerListEntry;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@Mixin(net.minecraft.client.network.ClientPlayNetworkHandler.class)
|
||||
public interface ClientPlayNetworkHandlerAccessor {
|
||||
@Accessor("playerListEntries")
|
||||
Map<UUID, PlayerListEntry> playerListEntries();
|
||||
|
||||
@Accessor("listedPlayerListEntries")
|
||||
Set<PlayerListEntry> listedPlayerListEntries();
|
||||
}
|
|
@ -1,119 +1,169 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.command.CommandManager;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import land.chipmunk.chipmunkmod.modules.*;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.command.CommandRegistryAccess;
|
||||
import net.minecraft.network.encryption.NetworkEncryptionUtils;
|
||||
import net.minecraft.network.message.LastSeenMessagesCollector;
|
||||
import net.minecraft.network.message.MessageBody;
|
||||
import net.minecraft.network.message.MessageChain;
|
||||
import net.minecraft.network.message.MessageSignatureData;
|
||||
import net.minecraft.network.packet.c2s.play.ChatMessageC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.GameMessageS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket;
|
||||
import net.minecraft.registry.DynamicRegistryManager;
|
||||
import net.minecraft.resource.featuretoggle.FeatureSet;
|
||||
import net.minecraft.text.PlainTextContent;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableTextContent;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Mixin(value = net.minecraft.client.network.ClientPlayNetworkHandler.class, priority = 1001)
|
||||
public class ClientPlayNetworkHandlerMixin {
|
||||
@Final
|
||||
@Shadow private FeatureSet enabledFeatures;
|
||||
@Final
|
||||
@Shadow private DynamicRegistryManager.Immutable combinedDynamicRegistries;
|
||||
@Shadow private LastSeenMessagesCollector lastSeenMessagesCollector;
|
||||
@Shadow private MessageChain.Packer messagePacker;
|
||||
|
||||
@Inject(method = "onGameJoin", at = @At("TAIL"))
|
||||
private void onGameJoin (GameJoinS2CPacket packet, CallbackInfo ci) {
|
||||
final CommandRegistryAccess commandRegistryAccess = CommandRegistryAccess.of(this.combinedDynamicRegistries, this.enabledFeatures);
|
||||
|
||||
KaboomCheck.INSTANCE.onJoin();
|
||||
CommandManager.INSTANCE = new CommandManager(ChipmunkMod.CONFIG.commands.prefix, commandRegistryAccess);
|
||||
SelfCare.INSTANCE.onJoin();
|
||||
CommandCore.INSTANCE.init();
|
||||
SongPlayer.INSTANCE.coreReady();
|
||||
RainbowName.INSTANCE.init();
|
||||
ChomeNSBotCommandSuggestions.INSTANCE.init();
|
||||
ChomeNSAuth.INSTANCE.init();
|
||||
CustomChat.INSTANCE.init();
|
||||
}
|
||||
|
||||
@Inject(method = "onGameMessage", at = @At("HEAD"), cancellable = true)
|
||||
private void onGameMessage (GameMessageS2CPacket packet, CallbackInfo ci) {
|
||||
final Text message = packet.content();
|
||||
|
||||
try {
|
||||
if (RainbowName.INSTANCE.enabled) {
|
||||
if (message.getString().contains("Your nickname is now ") || message.getString().contains("Nickname changed.")) {
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (((TranslatableTextContent) message.getContent()).getKey().equals("advMode.setCommand.success")) {
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
} catch (ClassCastException ignored) {}
|
||||
|
||||
for (Listener listener : ListenerManager.listeners) {
|
||||
listener.chatMessageReceived(message);
|
||||
}
|
||||
|
||||
try {
|
||||
final String suggestionId = message.getSiblings().getFirst().getString();
|
||||
final String authId = ((PlainTextContent) message.getContent()).string();
|
||||
|
||||
if (suggestionId.equals(ChomeNSBotCommandSuggestions.ID) || authId.equals(ChomeNSAuth.INSTANCE.id)) {
|
||||
ci.cancel();
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
@Inject(method = "sendChatMessage", at = @At("HEAD"), cancellable = true)
|
||||
private void sendChatMessage (String chatText, CallbackInfo ci) {
|
||||
final CommandManager commandManager = CommandManager.INSTANCE;
|
||||
|
||||
final String secret = String.valueOf(Chat.secret);
|
||||
|
||||
if (chatText.startsWith(commandManager.prefix)) {
|
||||
commandManager.executeCommand(chatText.substring(commandManager.prefix.length()));
|
||||
|
||||
ci.cancel();
|
||||
} else if (!chatText.startsWith("/") && !chatText.startsWith(secret)) {
|
||||
CustomChat.INSTANCE.chat(chatText);
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
if (chatText.startsWith(secret)) {
|
||||
final String content = chatText.substring(secret.length());
|
||||
|
||||
Instant instant = Instant.now();
|
||||
long l = NetworkEncryptionUtils.SecureRandomUtil.nextLong();
|
||||
LastSeenMessagesCollector.LastSeenMessages lastSeenMessages = this.lastSeenMessagesCollector.collect();
|
||||
MessageSignatureData messageSignatureData = this.messagePacker.pack(new MessageBody(content, instant, l, lastSeenMessages.lastSeen()));
|
||||
MinecraftClient.getInstance().getNetworkHandler().sendPacket(new ChatMessageC2SPacket(content, instant, l, messageSignatureData, lastSeenMessages.update()));
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.command.CommandManager;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import land.chipmunk.chipmunkmod.modules.*;
|
||||
import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.hud.InGameHud;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.command.CommandRegistryAccess;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.network.packet.s2c.play.*;
|
||||
import net.minecraft.registry.DynamicRegistryManager;
|
||||
import net.minecraft.resource.featuretoggle.FeatureSet;
|
||||
import net.minecraft.text.PlainTextContent;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableTextContent;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(value = ClientPlayNetworkHandler.class, priority = 1001)
|
||||
public abstract class ClientPlayNetworkHandlerMixin {
|
||||
@Final
|
||||
@Shadow
|
||||
private FeatureSet enabledFeatures;
|
||||
@Final
|
||||
@Shadow
|
||||
private DynamicRegistryManager.Immutable combinedDynamicRegistries;
|
||||
@Shadow
|
||||
private CommandDispatcher<CommandSource> commandDispatcher;
|
||||
|
||||
@Shadow public abstract ClientWorld getWorld ();
|
||||
|
||||
@Inject(method = "onGameJoin", at = @At("TAIL"))
|
||||
private void onGameJoin (final GameJoinS2CPacket packet, final CallbackInfo ci) {
|
||||
final CommandRegistryAccess commandRegistryAccess = CommandRegistryAccess.of(this.combinedDynamicRegistries, this.enabledFeatures);
|
||||
|
||||
KaboomCheck.INSTANCE.onJoin();
|
||||
CommandManager.INSTANCE = new CommandManager(ChipmunkMod.CONFIG.commands.prefix, commandRegistryAccess);
|
||||
SelfCare.INSTANCE.onJoin();
|
||||
CommandCore.INSTANCE.init();
|
||||
SongPlayer.INSTANCE.coreReady();
|
||||
RainbowName.INSTANCE.init();
|
||||
ChomeNSBotCommandSuggestions.INSTANCE.init();
|
||||
}
|
||||
|
||||
@Inject(method = "onCommandTree", at = @At("TAIL"))
|
||||
private void onCommandTree (final CommandTreeS2CPacket packet, final CallbackInfo ci) {
|
||||
KaboomCheck.INSTANCE.onCommandTree(this.commandDispatcher);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "onGameMessage",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/network/message/MessageHandler;onGameMessage(Lnet/minecraft/text/Text;Z)V"
|
||||
),
|
||||
cancellable = true
|
||||
)
|
||||
private void onGameMessage (final GameMessageS2CPacket packet, final CallbackInfo ci) {
|
||||
final Text message = packet.content();
|
||||
|
||||
if (
|
||||
(
|
||||
RainbowName.INSTANCE.enabled &&
|
||||
(
|
||||
message.getString().startsWith("Your nickname is now ") ||
|
||||
message.getString().startsWith("Nickname changed.")
|
||||
)
|
||||
) ||
|
||||
(
|
||||
message.getContent() instanceof final TranslatableTextContent translatableTextContent &&
|
||||
(
|
||||
translatableTextContent.getKey().equals("advMode.setCommand.success")
|
||||
|| translatableTextContent.getKey().equals("قيادة المجموعة: %s")
|
||||
)
|
||||
)
|
||||
) {
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
for (final Listener listener : ListenerManager.listeners) {
|
||||
listener.chatMessageReceived(message);
|
||||
}
|
||||
|
||||
if (
|
||||
message.getSiblings().size() > 1
|
||||
&& message.getSiblings().getFirst().getContent() instanceof final PlainTextContent textContent
|
||||
&& textContent.string().equals(ChomeNSBotCommandSuggestions.REQUEST_SUGGESTIONS_ID)
|
||||
) ci.cancel();
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "onOverlayMessage",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/gui/hud/InGameHud;setOverlayMessage(Lnet/minecraft/text/Text;Z)V"
|
||||
)
|
||||
)
|
||||
private void onOverlayMessage (final InGameHud instance, final Text message, final boolean tinted, final Operation<Void> original) {
|
||||
for (final Listener listener : ListenerManager.listeners) {
|
||||
listener.overlayMessageReceived(message);
|
||||
}
|
||||
|
||||
original.call(instance, message, tinted);
|
||||
|
||||
// checking for the chomens bot selector message doesn't really
|
||||
// do much here since the message is just an empty string
|
||||
// that gets sent only when you join (or the bot restarts),
|
||||
// so I do not ignore them
|
||||
}
|
||||
|
||||
@Inject(method = "sendChatMessage", at = @At("HEAD"), cancellable = true)
|
||||
private void sendChatMessage (final String content, final CallbackInfo ci) {
|
||||
final CommandManager commandManager = CommandManager.INSTANCE;
|
||||
if (content.startsWith(commandManager.prefix)) {
|
||||
commandManager.executeCommand(content.substring(commandManager.prefix.length()));
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Chat.NEXT_CHAT_PLAYER.get()) {
|
||||
Chat.NEXT_CHAT_PLAYER.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
CustomChat.INSTANCE.chat(content);
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "onPlayerPositionLook", at = @At("TAIL"))
|
||||
private void setPosition (final PlayerPositionLookS2CPacket packet, final CallbackInfo ci) {
|
||||
final Vec3d position = packet.change().position();
|
||||
|
||||
final BlockPos origin = CommandCore.INSTANCE.origin;
|
||||
if (origin == null) {
|
||||
CommandCore.INSTANCE.move(position);
|
||||
return;
|
||||
}
|
||||
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
final ClientPlayerEntity player = client.player;
|
||||
|
||||
if (player == null) return;
|
||||
|
||||
final int distanceSquared = player.getChunkPos().getSquaredDistance(new ChunkPos(origin));
|
||||
final int distance = (int) Math.sqrt(distanceSquared);
|
||||
|
||||
if (distance > getWorld().getSimulationDistance()) {
|
||||
CommandCore.INSTANCE.alreadyFilled = true;
|
||||
CommandCore.INSTANCE.move(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,44 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.entity.MovementType;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec2f;
|
||||
import land.chipmunk.chipmunkmod.modules.CommandCore;
|
||||
|
||||
@Mixin(ClientPlayerEntity.class)
|
||||
public class ClientPlayerEntityMixin {
|
||||
@Unique private static MinecraftClient CLIENT = MinecraftClient.getInstance();
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "move")
|
||||
public void move (MovementType type, Vec3d relPos, CallbackInfo ci) {
|
||||
if ((ClientPlayerEntity) (Object) this != CLIENT.player) return;
|
||||
|
||||
final Vec3d position = ((ClientPlayerEntity) (Object) this).getPos().add(relPos);
|
||||
|
||||
final ClientWorld world = CLIENT.getNetworkHandler().getWorld();
|
||||
|
||||
final BlockPos origin = CommandCore.INSTANCE.origin;
|
||||
if (origin == null) { CommandCore.INSTANCE.move(position); return; }
|
||||
final int distance = (int) Math.sqrt(new Vec2f(origin.getX() / 16, origin.getZ() / 16).distanceSquared(new Vec2f((int) position.getX() / 16, (int) position.getZ() / 16)));
|
||||
if (distance > world.getSimulationDistance()) {
|
||||
CommandCore.INSTANCE.clientPlayerEntityFilled = true;
|
||||
CommandCore.INSTANCE.move(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import land.chipmunk.chipmunkmod.modules.CommandCore;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.World;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ClientPlayerEntity.class)
|
||||
public abstract class ClientPlayerEntityMixin extends Entity {
|
||||
@Shadow
|
||||
@Final
|
||||
public ClientPlayNetworkHandler networkHandler;
|
||||
|
||||
public ClientPlayerEntityMixin (final EntityType<?> type, final World world) {
|
||||
super(type, world);
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "move")
|
||||
public void move (final CallbackInfo ci) {
|
||||
final BlockPos origin = CommandCore.INSTANCE.origin;
|
||||
if (origin == null) {
|
||||
CommandCore.INSTANCE.move(this.getPos());
|
||||
return;
|
||||
}
|
||||
|
||||
final int distanceSquared = this.getChunkPos().getSquaredDistance(new ChunkPos(origin));
|
||||
final int distance = (int) Math.sqrt(distanceSquared);
|
||||
|
||||
if (distance > networkHandler.getWorld().getSimulationDistance()) {
|
||||
CommandCore.INSTANCE.alreadyFilled = true;
|
||||
CommandCore.INSTANCE.move(this.getPos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.ParseResults;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.context.CommandContextBuilder;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(CommandDispatcher.class)
|
||||
public class CommandDispatcherMixin<S> {
|
||||
@Inject(method = "parseNodes", at = @At("HEAD"), cancellable = true, /* important --> */ remap = false)
|
||||
private void parseNodes (CommandNode<S> node, StringReader originalReader, CommandContextBuilder<S> contextSoFar, CallbackInfoReturnable<ParseResults<S>> cir) {
|
||||
// correct way to patch this?
|
||||
// if (node.getRelevantNodes(originalReader).size() > 127) {
|
||||
// cir.setReturnValue(new ParseResults<>(contextSoFar));
|
||||
//
|
||||
// cir.cancel();
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -12,12 +12,23 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|||
|
||||
@Mixin(ElderGuardianAppearanceParticle.Factory.class)
|
||||
public class ElderGuardianAppearanceParticleMixin {
|
||||
@Inject(method = "createParticle(Lnet/minecraft/particle/SimpleParticleType;Lnet/minecraft/client/world/ClientWorld;DDDDDD)Lnet/minecraft/client/particle/Particle;", at = @At("HEAD"), cancellable = true)
|
||||
private void testClient$limitGuardianParticles(SimpleParticleType defaultParticleType, ClientWorld clientWorld, double d, double e, double f, double g, double h, double i, CallbackInfoReturnable<Particle> cir) {
|
||||
if(SharedVariables.elderGuardianParticleTimer > 0) {
|
||||
cir.setReturnValue(null);
|
||||
cir.cancel();
|
||||
}
|
||||
SharedVariables.elderGuardianParticleTimer = 200;
|
||||
@Inject(
|
||||
method = "createParticle(Lnet/minecraft/particle/SimpleParticleType;Lnet/minecraft/client/world/ClientWorld;DDDDDD)Lnet/minecraft/client/particle/Particle;",
|
||||
at = @At("RETURN"),
|
||||
cancellable = true
|
||||
)
|
||||
private void createParticle (
|
||||
final SimpleParticleType simpleParticleType,
|
||||
final ClientWorld clientWorld,
|
||||
final double d,
|
||||
final double e,
|
||||
final double f,
|
||||
final double g,
|
||||
final double h,
|
||||
final double i,
|
||||
final CallbackInfoReturnable<Particle> cir
|
||||
) {
|
||||
// slash scare command
|
||||
cir.setReturnValue(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Identifier.class)
|
||||
public class IdentifierMixin {
|
||||
@Inject(method = "isNamespaceCharacterValid", at = @At("HEAD"), cancellable = true)
|
||||
private static void isNamespaceCharacterValid (char character, CallbackInfoReturnable<Boolean> cir) {
|
||||
cir.setReturnValue(true);
|
||||
|
||||
cir.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "isNamespaceValid", at = @At("HEAD"), cancellable = true)
|
||||
private static void isNamespaceValid (String namespace, CallbackInfoReturnable<Boolean> cir) {
|
||||
cir.setReturnValue(true);
|
||||
|
||||
cir.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "validateNamespace", at = @At("HEAD"), cancellable = true)
|
||||
private static void validateNamespace(String namespace, String path, CallbackInfoReturnable<String> cir) {
|
||||
cir.setReturnValue(namespace);
|
||||
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.client.Keyboard;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.Slice;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Keyboard.class)
|
||||
public class KeyboardMixin {
|
||||
|
||||
// Don't @ me. It half-works
|
||||
// LUNA WHAT THE FUCK IS THIS MIXIN AM I SUPPOSED TO UNDERSTAND THIS
|
||||
// lol
|
||||
@Redirect(method = "onKey(JIIII)V", at = @At(value = "FIELD", target = "Lnet/minecraft/client/MinecraftClient;currentScreen:Lnet/minecraft/client/gui/screen/Screen;", opcode = Opcodes.GETFIELD) )
|
||||
private Screen currentScreen(MinecraftClient instance) {
|
||||
// if (GuiMoveModule.instance.isEnabled) {
|
||||
// return null;
|
||||
// } else {
|
||||
return instance.currentScreen;
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -1,16 +1,14 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.client.session.Session;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(net.minecraft.client.MinecraftClient.class)
|
||||
public interface MinecraftClientAccessor {
|
||||
@Accessor("session")
|
||||
Session session ();
|
||||
|
||||
@Mutable
|
||||
@Accessor("session")
|
||||
void session (Session session);
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.session.Session;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public interface MinecraftClientAccessor {
|
||||
@Mutable
|
||||
@Accessor("session")
|
||||
void session (Session session);
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
import net.minecraft.block.Block;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Block.class)
|
||||
public class PlayerEntityMixin {
|
||||
//slippery world was here
|
||||
//TODO: remove
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.client.network.PlayerListEntry;
|
||||
import net.minecraft.world.GameMode;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(PlayerListEntry.class)
|
||||
public interface PlayerListEntryAccessor {
|
||||
@Accessor("gameMode")
|
||||
void setGameMode (GameMode gameMode);
|
||||
|
||||
@Accessor("latency")
|
||||
void setLatency (int latency);
|
||||
}
|
|
@ -9,9 +9,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|||
|
||||
@Mixin(SoundSystem.class)
|
||||
public class SoundSystemMixin {
|
||||
@Inject(method = "getAdjustedPitch", at = @At("HEAD"), cancellable = true)
|
||||
private void getAdjustedPitch (SoundInstance sound, CallbackInfoReturnable<Float> cir) {
|
||||
@Inject(method = "getAdjustedPitch", at = @At("RETURN"), cancellable = true)
|
||||
private void getAdjustedPitch (final SoundInstance sound, final CallbackInfoReturnable<Float> cir) {
|
||||
cir.setReturnValue(sound.getPitch());
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,21 +8,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|||
|
||||
@Mixin(StringHelper.class)
|
||||
public class StringHelperMixin {
|
||||
@Inject(method = "truncateChat", at = @At("HEAD"), cancellable = true)
|
||||
private static void truncateChat (String text, CallbackInfoReturnable<String> cir) {
|
||||
cir.setReturnValue(text);
|
||||
cir.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "stripTextFormat", at = @At("HEAD"), cancellable = true)
|
||||
private static void stripTextFormat(String text, CallbackInfoReturnable<String> cir) {
|
||||
cir.setReturnValue(text);
|
||||
cir.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "isValidChar", at = @At("HEAD"), cancellable = true)
|
||||
private static void isValidChar (char chr, CallbackInfoReturnable<Boolean> cir) {
|
||||
cir.setReturnValue(chr >= ' ' && chr != '\u007f');
|
||||
cir.cancel();
|
||||
@Inject(method = "isValidChar", at = @At("RETURN"), cancellable = true)
|
||||
private static void isValidChar (final char c, final CallbackInfoReturnable<Boolean> cir) {
|
||||
// very legal [NUL] [LF] § Allowance.
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(TextFieldWidget.class)
|
||||
public class TextFieldWidgetMixin {
|
||||
@Shadow private int maxLength;
|
||||
|
||||
@Inject(method = "setMaxLength", at = @At("HEAD"), cancellable = true)
|
||||
private void setMaxLength (int length, CallbackInfo ci) {
|
||||
this.maxLength = Integer.MAX_VALUE;
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import net.minecraft.text.StringVisitable;
|
||||
import net.minecraft.text.Style;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(Text.class)
|
||||
public interface TextMixin {
|
||||
@Inject(method = "visit(Lnet/minecraft/text/StringVisitable$Visitor;)Ljava/util/Optional;", at = @At(value = "INVOKE", target = "Lnet/minecraft/text/Text;visit(Lnet/minecraft/text/StringVisitable$Visitor;)Ljava/util/Optional;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
|
||||
private <T> void testclient$preventVisitMethodCrash(StringVisitable.Visitor<T> visitor, CallbackInfoReturnable<Optional<T>> cir, Optional optional, Iterator var3, Text text) {
|
||||
if(text == null) cir.setReturnValue(Optional.empty());
|
||||
}
|
||||
@Inject(method = "visit(Lnet/minecraft/text/StringVisitable$StyledVisitor;Lnet/minecraft/text/Style;)Ljava/util/Optional;", at = @At(value = "INVOKE", target = "Lnet/minecraft/text/Text;visit(Lnet/minecraft/text/StringVisitable$StyledVisitor;Lnet/minecraft/text/Style;)Ljava/util/Optional;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
|
||||
private <T> void testclient$preventVisitMethodCrash2(StringVisitable.StyledVisitor<T> styledVisitor, Style style, CallbackInfoReturnable<Optional<T>> cir, Style style2, Optional optional, Iterator var5, Text text) {
|
||||
if(text == null) cir.setReturnValue(Optional.empty());
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.mixin;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
@Mixin(Text.Serializer.class)
|
||||
public class TextSerializerMixin {
|
||||
@Unique private static final int LIMIT = 128;
|
||||
|
||||
@Unique private int i;
|
||||
|
||||
@Unique
|
||||
private boolean checkDepth (JsonElement element) {
|
||||
if (element.isJsonPrimitive()) return false;
|
||||
else if (i >= LIMIT) return true;
|
||||
|
||||
if (element.isJsonArray()) {
|
||||
i++;
|
||||
|
||||
for (JsonElement item : element.getAsJsonArray()) if (checkDepth(item)) return true;
|
||||
} else if (element.isJsonObject()) {
|
||||
final JsonObject object = element.getAsJsonObject();
|
||||
|
||||
JsonArray array;
|
||||
|
||||
if (object.has("extra")) array = object.get("extra").getAsJsonArray();
|
||||
else if (object.has("with")) array = object.get("with").getAsJsonArray();
|
||||
else return false;
|
||||
|
||||
i++;
|
||||
|
||||
for (JsonElement member : array) if (checkDepth(member)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Inject(method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/text/MutableText;", at = @At("HEAD"), cancellable = true)
|
||||
private void deserialize (JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext, CallbackInfoReturnable<MutableText> cir) {
|
||||
i = 0; // better way to do this?
|
||||
|
||||
final boolean overLimit = checkDepth(jsonElement);
|
||||
|
||||
if (!overLimit) return;
|
||||
|
||||
cir.setReturnValue(Text.empty()); // just ignores it
|
||||
|
||||
cir.cancel();
|
||||
}
|
||||
@Inject(method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/text/MutableText;", at = @At("HEAD"), cancellable = true)
|
||||
private void testclient$preventChatOverflowExploit(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext, CallbackInfoReturnable<MutableText> cir) {
|
||||
Throwable throwable = new Throwable();
|
||||
if(throwable.getStackTrace().length >= 700) cir.setReturnValue(Text.literal("TestClient prevented a text overflow exploit i think ("+throwable.getStackTrace().length+")").formatted(Formatting.GOLD));
|
||||
}
|
||||
}
|
|
@ -4,15 +4,17 @@ import net.minecraft.client.MinecraftClient;
|
|||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
|
||||
public class Chat {
|
||||
public static double secret = Math.random();
|
||||
public static final ThreadLocal<Boolean> NEXT_CHAT_PLAYER = ThreadLocal.withInitial(() -> false);
|
||||
|
||||
public static void sendChatMessage (String message) { sendChatMessage(message, false); }
|
||||
public static void sendChatMessage (String message, boolean usePlayerChat) {
|
||||
public static void sendChatMessage (final String message) { sendChatMessage(message, false); }
|
||||
|
||||
public static void sendChatMessage (final String message, final boolean usePlayerChat) {
|
||||
if (message == null) return;
|
||||
|
||||
final ClientPlayNetworkHandler networkHandler = MinecraftClient.getInstance().getNetworkHandler();
|
||||
if (usePlayerChat) NEXT_CHAT_PLAYER.set(true);
|
||||
|
||||
if (usePlayerChat) networkHandler.sendChatMessage(secret + message);
|
||||
else networkHandler.sendChatMessage(message);
|
||||
final ClientPlayNetworkHandler networkHandler = MinecraftClient.getInstance().getNetworkHandler();
|
||||
if (networkHandler == null) return;
|
||||
networkHandler.sendChatMessage(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
import com.google.common.hash.Hashing;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minecraft.text.PlainTextContent;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TextContent;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
public class ChomeNSAuth extends Listener {
|
||||
public static final ChomeNSAuth INSTANCE = new ChomeNSAuth();
|
||||
|
||||
public final String id = "chomens_bot_verify";
|
||||
|
||||
public ChomeNSAuth () {
|
||||
ListenerManager.addListener(this);
|
||||
}
|
||||
|
||||
public void init () {}
|
||||
|
||||
@Override
|
||||
public void chatMessageReceived(Text text) {
|
||||
final String authKey = ChipmunkMod.CONFIG.bots.chomens.authKey;
|
||||
|
||||
if (authKey == null) return;
|
||||
|
||||
final TextContent message = text.getContent();
|
||||
|
||||
if (!(message instanceof PlainTextContent)) return;
|
||||
|
||||
final String id = ((PlainTextContent) message).string();
|
||||
|
||||
if (!id.equals(this.id)) return;
|
||||
|
||||
final List<Text> children = text.getSiblings();
|
||||
|
||||
if (children.size() != 2) return;
|
||||
|
||||
if (!(children.getFirst().getContent() instanceof PlainTextContent)) return;
|
||||
|
||||
final String hash = ((PlainTextContent) children.getFirst().getContent()).string();
|
||||
|
||||
final long time = System.currentTimeMillis() / 10_000;
|
||||
|
||||
final String actual = Hashing.sha256()
|
||||
// very pro hash input
|
||||
.hashString(authKey + time, StandardCharsets.UTF_8)
|
||||
.toString()
|
||||
.substring(0, 8);
|
||||
|
||||
if (!hash.equals(actual)) return;
|
||||
|
||||
if (!(children.get(1).getContent() instanceof PlainTextContent)) return;
|
||||
|
||||
final String selector = ((PlainTextContent) children.get(1).getContent()).string();
|
||||
|
||||
final String toSendHash = Hashing.sha256()
|
||||
// very pro hash input
|
||||
.hashString(authKey + authKey + time + time, StandardCharsets.UTF_8)
|
||||
.toString()
|
||||
.substring(0, 8);
|
||||
|
||||
final Component toSend = Component.text(id)
|
||||
.append(Component.text(toSendHash));
|
||||
|
||||
final String toSendString = GsonComponentSerializer.gson().serialize(toSend);
|
||||
|
||||
System.out.println("Sending " + toSendString + " to " + selector);
|
||||
|
||||
CommandCore.INSTANCE.run("minecraft:tellraw " + selector + " " + toSendString);
|
||||
|
||||
CustomChat.INSTANCE.resetTotal();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.data.ChomeNSBotCommand;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
|
@ -9,82 +8,92 @@ import net.kyori.adventure.text.Component;
|
|||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.text.PlainTextContent;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableTextContent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ChomeNSBotCommandSuggestions extends Listener {
|
||||
public static final String ID = "chomens_bot_request_command_suggestion";
|
||||
public class ChomeNSBotCommandSuggestions implements Listener {
|
||||
public static final String BOT_SELECTOR_ID = "chomens_bot_selector";
|
||||
public static final String REQUEST_SUGGESTIONS_ID = "chomens_bot_request_command_suggestion";
|
||||
|
||||
public static ChomeNSBotCommandSuggestions INSTANCE = new ChomeNSBotCommandSuggestions(MinecraftClient.getInstance());
|
||||
|
||||
private final MinecraftClient client;
|
||||
|
||||
public boolean receivedSuggestions = false; // can be set through eval
|
||||
|
||||
public String botSelector = null;
|
||||
|
||||
public List<ChomeNSBotCommand> commands = new ArrayList<>();
|
||||
|
||||
public ChomeNSBotCommandSuggestions (MinecraftClient client) {
|
||||
public ChomeNSBotCommandSuggestions (final MinecraftClient client) {
|
||||
this.client = client;
|
||||
|
||||
ListenerManager.addListener(this);
|
||||
}
|
||||
|
||||
public void init () {}
|
||||
public void init () { }
|
||||
|
||||
@Override
|
||||
public void coreMoved () { forceRequest(); }
|
||||
public void coreMoved () {
|
||||
if (!receivedSuggestions) forceRequest();
|
||||
}
|
||||
|
||||
public void forceRequest () {
|
||||
final ClientPlayerEntity player = client.player;
|
||||
|
||||
if (player == null) return;
|
||||
if (botSelector == null || player == null) return;
|
||||
|
||||
final String selector = UUIDUtilities.selector(player.getUuid());
|
||||
|
||||
final Component component = Component
|
||||
.text(ID)
|
||||
.text(REQUEST_SUGGESTIONS_ID)
|
||||
.append(Component.text(selector));
|
||||
|
||||
final String serialized = GsonComponentSerializer.gson().serialize(component);
|
||||
|
||||
CommandCore.INSTANCE.run("tellraw @a[team=chomens_bot] " + serialized);
|
||||
// minecraft:tellraw @p[nbt={UUID:[I;6,9,6,9]} {...}
|
||||
CommandCore.INSTANCE.run(
|
||||
String.format(
|
||||
"%s %s %s",
|
||||
(KaboomCheck.INSTANCE.isKaboom ? "minecraft:tellraw" : "tellraw"),
|
||||
botSelector,
|
||||
serialized
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chatMessageReceived(Text message) {
|
||||
try {
|
||||
final List<Text> children = message.getSiblings();
|
||||
public void overlayMessageReceived (final Text message) {
|
||||
if (
|
||||
!(message.getContent() instanceof final TranslatableTextContent translatableTextContent)
|
||||
|| !translatableTextContent.getKey().isEmpty()
|
||||
|| translatableTextContent.getArgs().length != 2
|
||||
|| !(translatableTextContent.getArgs()[0] instanceof final String id)
|
||||
|| !id.equals(BOT_SELECTOR_ID)
|
||||
|| !(translatableTextContent.getArgs()[1] instanceof final String selector)
|
||||
) return;
|
||||
|
||||
if (children.isEmpty()) return;
|
||||
this.botSelector = selector;
|
||||
}
|
||||
|
||||
final Text textComponent = children.getFirst();
|
||||
@Override
|
||||
public void chatMessageReceived (final Text message) {
|
||||
final List<Text> children = message.getSiblings();
|
||||
if (children.isEmpty()) return;
|
||||
|
||||
if (!textComponent.getString().equals(ID)) return;
|
||||
final Text textComponent = children.getFirst();
|
||||
if (!textComponent.getString().equals(REQUEST_SUGGESTIONS_ID)) return;
|
||||
|
||||
commands = children.subList(1, children.size())
|
||||
.stream()
|
||||
.map(
|
||||
(eachComponent) -> {
|
||||
final ChomeNSBotCommand command = new ChomeNSBotCommand(
|
||||
ChipmunkMod.CONFIG.bots.chomens.prefix + ((PlainTextContent) eachComponent.getContent()).string(),
|
||||
ChomeNSBotCommand.TrustLevel.valueOf(eachComponent.getSiblings().getFirst().getString())
|
||||
);
|
||||
commands = children.stream()
|
||||
.skip(1)
|
||||
.map(ChomeNSBotCommand::fromText)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
|
||||
if (!Boolean.parseBoolean(eachComponent.getSiblings().get(1).getString())) return command;
|
||||
|
||||
final List<Text> subList = eachComponent.getSiblings().subList(2, eachComponent.getSiblings().size());
|
||||
|
||||
for (Text aliasComponent : subList) {
|
||||
final String alias = aliasComponent.getString();
|
||||
|
||||
command.aliases.add(alias);
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
)
|
||||
.toList();
|
||||
} catch (Exception ignored) {}
|
||||
receivedSuggestions = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,332 +1,482 @@
|
|||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.data.BlockArea;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import land.chipmunk.chipmunkmod.util.MathUtilities;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.CommandBlock;
|
||||
import net.minecraft.block.entity.CommandBlockBlockEntity;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.c2s.play.UpdateCommandBlockC2SPacket;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class CommandCore {
|
||||
private final MinecraftClient client;
|
||||
public boolean ready = false;
|
||||
public BlockPos origin;
|
||||
public BlockArea noPos;
|
||||
public BlockPos block;
|
||||
public BlockArea withPos;
|
||||
|
||||
private Timer timer;
|
||||
|
||||
private boolean shouldRefill = false;
|
||||
|
||||
public boolean runFillCommand = true;
|
||||
|
||||
public boolean clientPlayerEntityFilled = false;
|
||||
|
||||
public static CommandCore INSTANCE = new CommandCore(MinecraftClient.getInstance());
|
||||
|
||||
public CommandCore (MinecraftClient client) {
|
||||
this.client = client;
|
||||
reloadRelativeArea();
|
||||
}
|
||||
|
||||
public void init () {
|
||||
if (timer != null) cleanup();
|
||||
|
||||
final TimerTask task = new TimerTask() {
|
||||
public void run () {
|
||||
tick();
|
||||
}
|
||||
};
|
||||
|
||||
final TimerTask refillTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (clientPlayerEntityFilled) {
|
||||
clientPlayerEntityFilled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
check();
|
||||
|
||||
if (!shouldRefill) return;
|
||||
|
||||
refill();
|
||||
|
||||
shouldRefill = false;
|
||||
}
|
||||
};
|
||||
|
||||
timer = new Timer();
|
||||
|
||||
timer.schedule(task, 50, 50);
|
||||
|
||||
timer.schedule(refillTask, 50, 1000);
|
||||
|
||||
move(client.player.getPos());
|
||||
}
|
||||
|
||||
private void tick () {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null) {
|
||||
cleanup();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
reloadRelativeArea();
|
||||
}
|
||||
|
||||
public void reloadRelativeArea () {
|
||||
noPos = ChipmunkMod.CONFIG.core.relativeArea;
|
||||
}
|
||||
|
||||
public void check () {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null || withPos == null || !ready) return;
|
||||
|
||||
try {
|
||||
for (int x = withPos.start.getX(); x <= withPos.end.getX(); x++) {
|
||||
for (int y = withPos.start.getY(); y <= withPos.end.getY(); y++) {
|
||||
for (int z = withPos.start.getZ(); z <= withPos.end.getZ(); z++) {
|
||||
final BlockPos pos = new BlockPos(x, y, z);
|
||||
|
||||
final ClientWorld world = client.world;
|
||||
|
||||
if (world == null) return;
|
||||
|
||||
final Block block = world.getBlockState(pos).getBlock();
|
||||
|
||||
if (block instanceof CommandBlock) continue;
|
||||
|
||||
shouldRefill = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void move (Vec3d position) {
|
||||
final ClientWorld world = client.world;
|
||||
|
||||
if (world == null || noPos == null) return;
|
||||
|
||||
final DimensionType dimension = world.getDimension();
|
||||
|
||||
origin = new BlockPos(
|
||||
((int) position.getX() / 16) * 16,
|
||||
(int) MathUtilities.clamp(noPos.start.getY(), dimension.minY(), dimension.height()),
|
||||
((int) position.getZ() / 16) * 16
|
||||
);
|
||||
|
||||
withPos = new BlockArea(
|
||||
new BlockPos(
|
||||
noPos.start.getX() + origin.getX(),
|
||||
(int) MathUtilities.clamp(noPos.start.getY(), dimension.minY(), dimension.height()),
|
||||
noPos.start.getZ() + origin.getZ()
|
||||
),
|
||||
new BlockPos(
|
||||
noPos.end.getX() + origin.getX(),
|
||||
(int) MathUtilities.clamp(noPos.end.getY(), dimension.minY(), dimension.height()),
|
||||
noPos.end.getZ() + origin.getZ()
|
||||
)
|
||||
);
|
||||
|
||||
block = new BlockPos(withPos.start);
|
||||
refill();
|
||||
|
||||
for (Listener listener : ListenerManager.listeners) listener.coreMoved();
|
||||
if (!ready) {
|
||||
ready = true;
|
||||
|
||||
for (Listener listener : ListenerManager.listeners) listener.coreReady();
|
||||
}
|
||||
}
|
||||
|
||||
public void refill () {
|
||||
if (!runFillCommand || withPos == null) return;
|
||||
|
||||
final String command = String.format(
|
||||
KaboomCheck.INSTANCE.isKaboom ?
|
||||
"fill %s %s %s %s %s %s repeating_command_block replace" :
|
||||
"fill %s %s %s %s %s %s command_block",
|
||||
withPos.start.getX(),
|
||||
withPos.start.getY(),
|
||||
withPos.start.getZ(),
|
||||
|
||||
withPos.end.getX(),
|
||||
withPos.end.getY(),
|
||||
withPos.end.getZ()
|
||||
);
|
||||
|
||||
client.getNetworkHandler().sendChatCommand(command);
|
||||
}
|
||||
|
||||
public void incrementCurrentBlock () {
|
||||
if (withPos == null) return;
|
||||
|
||||
final BlockPos start = withPos.start;
|
||||
final BlockPos end = withPos.end;
|
||||
|
||||
if (start == null || end == null) return;
|
||||
|
||||
int x = block.getX();
|
||||
int y = block.getY();
|
||||
int z = block.getZ();
|
||||
|
||||
x++;
|
||||
|
||||
if (x > end.getX()) {
|
||||
x = start.getX();
|
||||
z++;
|
||||
}
|
||||
|
||||
if (z > end.getZ()) {
|
||||
z = start.getZ();
|
||||
y++;
|
||||
}
|
||||
|
||||
if (y > end.getY()) {
|
||||
x = start.getX();
|
||||
y = start.getY();
|
||||
z = start.getZ();
|
||||
}
|
||||
|
||||
block = new BlockPos(x, y, z);
|
||||
}
|
||||
|
||||
public void run (String command) {
|
||||
final ClientConnection connection = client.getNetworkHandler().getConnection();
|
||||
|
||||
if (block == null) return;
|
||||
|
||||
if (KaboomCheck.INSTANCE.isKaboom) {
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
command,
|
||||
CommandBlockBlockEntity.Type.AUTO,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
)
|
||||
);
|
||||
} else {
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
"",
|
||||
CommandBlockBlockEntity.Type.REDSTONE,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
command,
|
||||
CommandBlockBlockEntity.Type.REDSTONE,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
incrementCurrentBlock();
|
||||
}
|
||||
|
||||
public CompletableFuture<NbtCompound> runTracked (String command) {
|
||||
final ClientConnection connection = client.getNetworkHandler().getConnection();
|
||||
|
||||
if (block == null) return new CompletableFuture<>();
|
||||
|
||||
if (KaboomCheck.INSTANCE.isKaboom) {
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
command,
|
||||
CommandBlockBlockEntity.Type.AUTO,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
)
|
||||
);
|
||||
} else {
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
"",
|
||||
CommandBlockBlockEntity.Type.REDSTONE,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
command,
|
||||
CommandBlockBlockEntity.Type.REDSTONE,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
incrementCurrentBlock();
|
||||
|
||||
CompletableFuture<NbtCompound> future = new CompletableFuture<>();
|
||||
|
||||
final Timer timer = new Timer();
|
||||
|
||||
final TimerTask queryTask = new TimerTask() {
|
||||
public void run () {
|
||||
client.getNetworkHandler().getDataQueryHandler().queryBlockNbt(block, future::complete);
|
||||
|
||||
timer.cancel(); // ? Is this necesary?
|
||||
timer.purge();
|
||||
}
|
||||
};
|
||||
|
||||
timer.schedule(queryTask, 50);
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
public void cleanup () {
|
||||
if (timer == null) return;
|
||||
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
|
||||
withPos = null;
|
||||
block = null;
|
||||
ready = false;
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.CommandBlock;
|
||||
import net.minecraft.block.entity.CommandBlockBlockEntity;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.network.ClientPlayerInteractionManager;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.component.ComponentMap;
|
||||
import net.minecraft.component.DataComponentTypes;
|
||||
import net.minecraft.component.type.NbtComponent;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.play.UpdateCommandBlockC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.state.property.Property;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.*;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class CommandCore {
|
||||
public static CommandCore INSTANCE = new CommandCore(MinecraftClient.getInstance());
|
||||
|
||||
private final MinecraftClient client;
|
||||
|
||||
public boolean ready = false;
|
||||
public BlockPos origin;
|
||||
public BlockBox noPos;
|
||||
public BlockBox withPos;
|
||||
public BlockPos block;
|
||||
public boolean runFillCommand = true;
|
||||
public boolean alreadyFilled = false;
|
||||
|
||||
private Timer timer;
|
||||
private boolean shouldRefill = false;
|
||||
private DimensionType oldDimension;
|
||||
|
||||
public CommandCore (final MinecraftClient client) {
|
||||
this.client = client;
|
||||
reloadRelativeArea();
|
||||
}
|
||||
|
||||
public void init () {
|
||||
if (timer != null) cleanup();
|
||||
|
||||
final TimerTask task = new TimerTask() {
|
||||
public void run () {
|
||||
tick();
|
||||
}
|
||||
};
|
||||
|
||||
final TimerTask refillTask = new TimerTask() {
|
||||
@Override
|
||||
public void run () {
|
||||
if (alreadyFilled) {
|
||||
alreadyFilled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
check();
|
||||
|
||||
if (!shouldRefill) return;
|
||||
|
||||
refill();
|
||||
|
||||
shouldRefill = false;
|
||||
}
|
||||
};
|
||||
|
||||
timer = new Timer();
|
||||
|
||||
timer.schedule(task, 50, 50);
|
||||
|
||||
timer.schedule(refillTask, 50, 1000);
|
||||
|
||||
if (client.player == null) return;
|
||||
|
||||
move(client.player.getPos());
|
||||
}
|
||||
|
||||
private void tick () {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null) {
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
reloadRelativeArea();
|
||||
}
|
||||
|
||||
public void reloadRelativeArea () {
|
||||
noPos = ChipmunkMod.CONFIG.core.relativeArea;
|
||||
}
|
||||
|
||||
public void check () {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null || withPos == null || !ready) return;
|
||||
|
||||
final ClientPlayerEntity player = client.player;
|
||||
final ClientWorld world = client.world;
|
||||
|
||||
if (player == null || world == null) return;
|
||||
|
||||
if (oldDimension != null && !oldDimension.equals(world.getDimension())) move(client.player.getPos());
|
||||
|
||||
oldDimension = world.getDimension();
|
||||
|
||||
try {
|
||||
for (int x = withPos.getMinX(); x <= withPos.getMaxX(); x++) {
|
||||
for (int y = withPos.getMinY(); y <= withPos.getMaxY(); y++) {
|
||||
for (int z = withPos.getMinZ(); z <= withPos.getMaxZ(); z++) {
|
||||
final BlockPos pos = new BlockPos(x, y, z);
|
||||
|
||||
final Block block = world.getBlockState(pos).getBlock();
|
||||
|
||||
if (block instanceof CommandBlock) continue;
|
||||
|
||||
shouldRefill = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
ChipmunkMod.LOGGER.error("Error while checking if core needs refilling", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void move (final Vec3d position) {
|
||||
final ClientWorld world = client.world;
|
||||
if (world == null || noPos == null) return;
|
||||
|
||||
final DimensionType dimension = world.getDimension();
|
||||
|
||||
final int dimMinY = dimension.minY();
|
||||
final int dimMaxY = dimension.height() + dimMinY - 1; // -1 accounts for block at Y=0
|
||||
int yOffset = 0;
|
||||
if (noPos.getMinY() < dimMinY) {
|
||||
yOffset = dimMinY - noPos.getMinY();
|
||||
} else if (noPos.getMaxY() > dimMaxY) {
|
||||
yOffset = dimMaxY - noPos.getMaxY();
|
||||
}
|
||||
|
||||
origin = new BlockPos(
|
||||
((int) position.getX() / 16) * 16,
|
||||
noPos.getMinY() + yOffset,
|
||||
((int) position.getZ() / 16) * 16
|
||||
);
|
||||
|
||||
withPos = noPos.offset(origin.getX(), yOffset, origin.getZ());
|
||||
block = new BlockPos(withPos.getMinX(), withPos.getMinY(), withPos.getMinZ());
|
||||
refill();
|
||||
|
||||
final Timer timer = new Timer();
|
||||
|
||||
final TimerTask task = new TimerTask() {
|
||||
@Override
|
||||
public void run () {
|
||||
for (final Listener listener : ListenerManager.listeners) listener.coreMoved();
|
||||
if (!ready) {
|
||||
ready = true;
|
||||
|
||||
for (final Listener listener : ListenerManager.listeners) listener.coreReady();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
timer.schedule(task, 75);
|
||||
}
|
||||
|
||||
public void refill () {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (!runFillCommand || client.world == null || networkHandler == null || withPos == null) return;
|
||||
|
||||
final Chunk chunk = client.world.getChunk(withPos.getCenter());
|
||||
|
||||
if (chunk == null) return;
|
||||
|
||||
final String command = String.format(
|
||||
"fill %s %s %s %s %s %s command_block",
|
||||
|
||||
withPos.getMinX(),
|
||||
withPos.getMinY(),
|
||||
withPos.getMinZ(),
|
||||
|
||||
withPos.getMaxX(),
|
||||
withPos.getMaxY(),
|
||||
withPos.getMaxZ()
|
||||
);
|
||||
|
||||
runPlaceBlock(command);
|
||||
}
|
||||
|
||||
public void incrementCurrentBlock () {
|
||||
if (withPos == null) return;
|
||||
|
||||
int x = block.getX() + 1;
|
||||
int y = block.getY();
|
||||
int z = block.getZ();
|
||||
|
||||
if (x > withPos.getMaxX()) {
|
||||
x = withPos.getMinX();
|
||||
z++;
|
||||
if (z > withPos.getMaxZ()) {
|
||||
z = withPos.getMinZ();
|
||||
y++;
|
||||
if (y > withPos.getMaxY()) {
|
||||
y = withPos.getMinY();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
block = new BlockPos(x, y, z);
|
||||
}
|
||||
|
||||
public void run (final String command) {
|
||||
if (command.length() > 32767) return;
|
||||
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null) return;
|
||||
|
||||
final ClientConnection connection = networkHandler.getConnection();
|
||||
|
||||
if (block == null) return;
|
||||
|
||||
ChipmunkMod.LOGGER.info("Executing core command: {}", command);
|
||||
|
||||
if (KaboomCheck.INSTANCE.isKaboom) {
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
command,
|
||||
CommandBlockBlockEntity.Type.AUTO,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
)
|
||||
);
|
||||
} else {
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
"",
|
||||
CommandBlockBlockEntity.Type.REDSTONE,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
command,
|
||||
CommandBlockBlockEntity.Type.REDSTONE,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
incrementCurrentBlock();
|
||||
}
|
||||
|
||||
public CompletableFuture<NbtCompound> runTracked (final String command) {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null) return new CompletableFuture<>();
|
||||
|
||||
final ClientConnection connection = networkHandler.getConnection();
|
||||
|
||||
if (block == null) return new CompletableFuture<>();
|
||||
|
||||
if (KaboomCheck.INSTANCE.isKaboom) {
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
command,
|
||||
CommandBlockBlockEntity.Type.AUTO,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
)
|
||||
);
|
||||
} else {
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
"",
|
||||
CommandBlockBlockEntity.Type.REDSTONE,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
connection.send(
|
||||
new UpdateCommandBlockC2SPacket(
|
||||
block,
|
||||
command,
|
||||
CommandBlockBlockEntity.Type.REDSTONE,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
final CompletableFuture<NbtCompound> future = new CompletableFuture<>();
|
||||
|
||||
final Timer timer = new Timer();
|
||||
|
||||
final BlockPos oldBlock = block;
|
||||
|
||||
final TimerTask queryTask = new TimerTask() {
|
||||
public void run () {
|
||||
client.getNetworkHandler().getDataQueryHandler().queryBlockNbt(oldBlock, future::complete);
|
||||
}
|
||||
};
|
||||
|
||||
timer.schedule(queryTask, 50);
|
||||
|
||||
incrementCurrentBlock();
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
public void runPlaceBlock (final String command) {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
if (networkHandler == null) return;
|
||||
|
||||
final ClientConnection connection = networkHandler.getConnection();
|
||||
|
||||
final ClientPlayerEntity player = client.player;
|
||||
final ClientWorld world = client.world;
|
||||
|
||||
if (player == null || world == null || !player.isInCreativeMode()) return;
|
||||
|
||||
final DimensionType dimensionType = world.getDimension();
|
||||
|
||||
if (
|
||||
player.getPos().getY() < dimensionType.minY()
|
||||
|| player.getPos().getY() > dimensionType.height() + dimensionType.minY()
|
||||
) {
|
||||
networkHandler.sendChatCommand(command);
|
||||
return;
|
||||
}
|
||||
|
||||
final ClientPlayerInteractionManager interactionManager = client.interactionManager;
|
||||
if (interactionManager == null) return;
|
||||
|
||||
final float yaw = player.getYaw();
|
||||
final float pitch = player.getPitch();
|
||||
|
||||
// Anti Block when flying around
|
||||
final BlockPos position = player.getBlockPos().add(
|
||||
(int) Math.round(3 * Math.cos(Math.toRadians(yaw))),
|
||||
3 * (pitch < 0 ? -1 : 1),
|
||||
(int) Math.round(3 * Math.sin(Math.toRadians(yaw)))
|
||||
);
|
||||
|
||||
// stolen from two five hundred million dollars
|
||||
final BlockState oldBlockState = world.getBlockState(position);
|
||||
|
||||
final int freeHotBarSlot = player.getInventory().getEmptySlot();
|
||||
final int slot = 36 + freeHotBarSlot;
|
||||
|
||||
final int oldSelectedSlot = player.getInventory().selectedSlot;
|
||||
final ItemStack oldStack = player.getInventory().getStack(slot).copy();
|
||||
|
||||
final ItemStack commandBlock = new ItemStack(Items.COMMAND_BLOCK);
|
||||
|
||||
final NbtCompound data = new NbtCompound();
|
||||
data.putString("id", "minecraft:command_block");
|
||||
data.putString("Command", command);
|
||||
data.putBoolean("auto", true);
|
||||
|
||||
final NbtCompound blockEntityTag = new NbtCompound();
|
||||
blockEntityTag.put("BlockEntityTag", data);
|
||||
|
||||
commandBlock.applyComponentsFrom(
|
||||
ComponentMap.builder()
|
||||
.add(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(blockEntityTag))
|
||||
.add(DataComponentTypes.BLOCK_ENTITY_DATA, NbtComponent.of(data))
|
||||
.build()
|
||||
);
|
||||
|
||||
connection.send(new CreativeInventoryActionC2SPacket(slot, commandBlock));
|
||||
|
||||
if (oldSelectedSlot != freeHotBarSlot) {
|
||||
connection.send(new UpdateSelectedSlotC2SPacket(freeHotBarSlot));
|
||||
}
|
||||
|
||||
interactionManager.breakBlock(position);
|
||||
interactionManager.interactBlock(
|
||||
player,
|
||||
Hand.MAIN_HAND,
|
||||
new BlockHitResult(
|
||||
new Vec3d(position),
|
||||
Direction.UP,
|
||||
position,
|
||||
false
|
||||
)
|
||||
);
|
||||
|
||||
if (oldSelectedSlot != freeHotBarSlot) {
|
||||
connection.send(new UpdateSelectedSlotC2SPacket(oldSelectedSlot));
|
||||
}
|
||||
connection.send(new CreativeInventoryActionC2SPacket(slot, oldStack));
|
||||
|
||||
final Timer timer = new Timer();
|
||||
|
||||
final TimerTask task = new TimerTask() {
|
||||
@Override
|
||||
public void run () {
|
||||
final StringBuilder command = new StringBuilder(
|
||||
String.format(
|
||||
"setblock %d %d %d %s",
|
||||
|
||||
position.getX(),
|
||||
position.getY(),
|
||||
position.getZ(),
|
||||
|
||||
Registries.BLOCK.getId(oldBlockState.getBlock())
|
||||
)
|
||||
);
|
||||
|
||||
if (!oldBlockState.getProperties().isEmpty()) {
|
||||
command.append('[');
|
||||
|
||||
for (final Property<?> property : oldBlockState.getProperties()) {
|
||||
command.append(property.getName())
|
||||
.append('=')
|
||||
.append(Util.getValueAsString(property, property.getType()))
|
||||
.append(',');
|
||||
}
|
||||
|
||||
command.deleteCharAt(command.length() - 1);
|
||||
|
||||
command.append(']');
|
||||
}
|
||||
|
||||
CommandCore.this.run(command.toString());
|
||||
}
|
||||
};
|
||||
|
||||
timer.schedule(task, 100); // assuming the core has already been filled at this point
|
||||
}
|
||||
|
||||
public void cleanup () {
|
||||
if (timer == null) return;
|
||||
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
|
||||
withPos = null;
|
||||
block = null;
|
||||
ready = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +1,36 @@
|
|||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class CommandLoopManager {
|
||||
public static final CommandLoopManager INSTANCE = new CommandLoopManager(CommandCore.INSTANCE);
|
||||
private final CommandCore core;
|
||||
public List<CommandLoop> commandLoops = new ArrayList<>();
|
||||
|
||||
public CommandLoopManager (CommandCore core) {
|
||||
public CommandLoopManager (final CommandCore core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public static final CommandLoopManager INSTANCE = new CommandLoopManager(CommandCore.INSTANCE);
|
||||
|
||||
public int loopCommand (String command, long interval) {
|
||||
public int loopCommand (final String command, final long interval) {
|
||||
final CommandLoop loop = new CommandLoop(this.core, command, interval);
|
||||
if (!commandLoops.add(loop)) return -1;
|
||||
commandLoops.add(loop);
|
||||
return commandLoops.size() - 1;
|
||||
}
|
||||
|
||||
public boolean removeAndStop (CommandLoop loop) {
|
||||
public boolean removeAndStop (final CommandLoop loop) {
|
||||
loop.stop();
|
||||
return commandLoops.remove(loop);
|
||||
}
|
||||
|
||||
public boolean removeAndStop (int id) {
|
||||
public boolean removeAndStop (final int id) {
|
||||
return removeAndStop(commandLoops.get(id));
|
||||
}
|
||||
|
||||
public void clearLoops () {
|
||||
for (CommandLoop loop : this.commandLoops) loop.stop();
|
||||
for (final CommandLoop loop : this.commandLoops) loop.stop();
|
||||
commandLoops.clear();
|
||||
}
|
||||
|
||||
|
@ -45,7 +42,7 @@ public class CommandLoopManager {
|
|||
public long interval;
|
||||
private Timer timer;
|
||||
|
||||
public CommandLoop (CommandCore core, String command, long interval) {
|
||||
public CommandLoop (final CommandCore core, final String command, final long interval) {
|
||||
this.core = core;
|
||||
this.command = command;
|
||||
this.interval = interval;
|
||||
|
@ -53,8 +50,9 @@ public class CommandLoopManager {
|
|||
timer.schedule(this.createTimerTask(), interval, interval);
|
||||
}
|
||||
|
||||
private long interval (long interval) {
|
||||
if (timer == null) throw new IllegalStateException("Attempted to set the interval of a stopped command loop");
|
||||
private long interval (final long interval) {
|
||||
if (timer == null)
|
||||
throw new IllegalStateException("Attempted to set the interval of a stopped command loop");
|
||||
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.gson.JsonElement;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CustomChat {
|
||||
private final MinecraftClient client;
|
||||
|
||||
public static final CustomChat INSTANCE = new CustomChat(MinecraftClient.getInstance());
|
||||
|
||||
public boolean enabled = true;
|
||||
|
||||
public String format;
|
||||
|
||||
private Timer timer;
|
||||
|
||||
private int total = 0;
|
||||
|
||||
public CustomChat (MinecraftClient client) {
|
||||
this.client = client;
|
||||
|
||||
reloadFormat();
|
||||
}
|
||||
|
||||
public void init () {
|
||||
final TimerTask task = new TimerTask() {
|
||||
public void run () {
|
||||
tick();
|
||||
}
|
||||
};
|
||||
|
||||
resetTotal();
|
||||
|
||||
timer = new Timer();
|
||||
timer.schedule(task, 0, 50);
|
||||
}
|
||||
|
||||
private void tick () {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler != null) return;
|
||||
|
||||
resetTotal();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
public void resetTotal() {
|
||||
total = 0;
|
||||
}
|
||||
|
||||
private void cleanup () {
|
||||
if (timer == null) return;
|
||||
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
}
|
||||
|
||||
public void reloadFormat () {
|
||||
final JsonElement formatString = ChipmunkMod.CONFIG.customChat.format;
|
||||
|
||||
if (formatString == null) format = "{\"translate\":\"chat.type.text\",\"with\":[\"USERNAME\",\"MESSAGE\"]}";
|
||||
else format = formatString.toString();
|
||||
}
|
||||
|
||||
public void chat (String message) {
|
||||
final ClientPlayerEntity player = client.player;
|
||||
|
||||
if (!enabled || !player.hasPermissionLevel(2) || !player.isCreative()) {
|
||||
Chat.sendChatMessage(message, true);
|
||||
return;
|
||||
}
|
||||
|
||||
final String username = MinecraftClient.getInstance().getSession().getUsername();
|
||||
|
||||
final String sanitizedMessage = message
|
||||
.replace("\\", "\\\\")
|
||||
.replace("\"", "\\\"");
|
||||
|
||||
final LegacyComponentSerializer serializer = LegacyComponentSerializer.legacyAmpersand();
|
||||
|
||||
final String randomized = String.valueOf(Math.random());
|
||||
|
||||
final Component deserialized = serializer.deserialize(message);
|
||||
final String messageWithColor = GsonComponentSerializer.gson().serialize(deserialized).replace("MESSAGE", randomized);
|
||||
|
||||
final String key = ChipmunkMod.CONFIG.bots.chomens.formatKey;
|
||||
|
||||
final String hash = key != null ?
|
||||
Hashing.sha256()
|
||||
.hashString(key + total, StandardCharsets.UTF_8)
|
||||
.toString()
|
||||
.substring(0, 8) :
|
||||
"";
|
||||
|
||||
total++;
|
||||
|
||||
try {
|
||||
// final MutablePlayerListEntry entry = Players.INSTANCE.getEntry(client.getNetworkHandler().getProfile().getId());
|
||||
|
||||
// final Component displayNameComponent = entry.displayName().asComponent();
|
||||
|
||||
// final String prefix = GsonComponentSerializer.gson().serialize(Component.join(JoinConfiguration.separator(Component.empty()), displayNameComponent.children().get(0)));
|
||||
// final String displayName = GsonComponentSerializer.gson().serialize(Component.join(JoinConfiguration.separator(Component.empty()), displayNameComponent.children().get(1)));
|
||||
|
||||
// TODO: make this code not ohio code.,.,
|
||||
String sanitizedFormat = format
|
||||
// .replace("\"PREFIX\"", prefix)
|
||||
// .replace("\"DISPLAYNAME\"", displayName)
|
||||
.replace("USERNAME", username)
|
||||
.replace("HASH", hash)
|
||||
.replace("{\"text\":\"MESSAGE\"}", messageWithColor)
|
||||
.replace("\"extra\":[\"MESSAGE\"],\"color\":", "\"extra\":[" + messageWithColor + "],\"color\":")
|
||||
.replace("MESSAGE", sanitizedMessage.replaceAll("&.", ""))
|
||||
.replace(randomized, "MESSAGE"); // ohio ohio
|
||||
|
||||
CommandCore.INSTANCE.run((KaboomCheck.INSTANCE.isKaboom ? "minecraft:tellraw @a " : "tellraw @a ") + sanitizedFormat);
|
||||
} catch (Exception e) {
|
||||
if (client.player == null) return;
|
||||
((Audience) client.player).sendMessage(Component.text(e.toString()).color(NamedTextColor.RED));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,83 +1,25 @@
|
|||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
import com.mojang.brigadier.suggestion.Suggestion;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.network.packet.s2c.play.CommandSuggestionsS2CPacket;
|
||||
import net.minecraft.command.CommandSource;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class KaboomCheck extends Listener {
|
||||
public class KaboomCheck {
|
||||
public static final KaboomCheck INSTANCE = new KaboomCheck();
|
||||
private static final String CHECKED_COMMAND_OP = "extras:prefix"; // Added circa 2018
|
||||
private static final String CHECKED_COMMAND = "minecraft:op"; // It'd be a bit weird for non-Kaboom servers to allow /op without OP...
|
||||
private final MinecraftClient client = MinecraftClient.getInstance();
|
||||
public boolean isKaboom = false;
|
||||
|
||||
private Timer timer = null;
|
||||
|
||||
private final MinecraftClient client;
|
||||
|
||||
public static final KaboomCheck INSTANCE = new KaboomCheck(MinecraftClient.getInstance());
|
||||
|
||||
public KaboomCheck (MinecraftClient client) {
|
||||
this.client = client;
|
||||
|
||||
ListenerManager.addListener(this);
|
||||
}
|
||||
|
||||
public void init () {}
|
||||
|
||||
public void onJoin () {
|
||||
final TimerTask task = new TimerTask() {
|
||||
public void run () {
|
||||
tick();
|
||||
}
|
||||
};
|
||||
|
||||
if (timer != null) cleanup();
|
||||
|
||||
timer = new Timer();
|
||||
|
||||
timer.schedule(task, 50, 50);
|
||||
|
||||
check();
|
||||
this.isKaboom = false;
|
||||
}
|
||||
|
||||
private void tick () {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
public void onCommandTree (final CommandDispatcher<CommandSource> dispatcher) {
|
||||
assert client.player != null; // We can only receive this packet while in a server
|
||||
final String checkedCommand = client.player.getPermissionLevel() == 4
|
||||
? CHECKED_COMMAND_OP : CHECKED_COMMAND;
|
||||
|
||||
if (networkHandler == null) cleanup();
|
||||
this.isKaboom = dispatcher.getRoot().getChild(checkedCommand) != null;
|
||||
}
|
||||
|
||||
private void check () {
|
||||
final CompletableFuture<CommandSuggestionsS2CPacket> future = TabComplete.INSTANCE.complete("/ver ");
|
||||
|
||||
future.thenApply((packet) -> {
|
||||
final Suggestions suggestions = packet.getSuggestions();
|
||||
|
||||
for (int i = 0; i < suggestions.getList().size(); i++) {
|
||||
final Suggestion suggestion = suggestions.getList().get(i);
|
||||
|
||||
if (suggestion.getText().equals("Extras")) {
|
||||
isKaboom = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void cleanup () {
|
||||
if (timer == null) return;
|
||||
|
||||
isKaboom = false;
|
||||
|
||||
timer.purge();
|
||||
timer.cancel();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.util.ColorUtilities;
|
||||
|
||||
|
||||
import land.chipmunk.chipmunkmod.util.RandomUtilities;
|
||||
import land.chipmunk.chipmunkmod.util.UUIDUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
@ -14,23 +16,21 @@ import java.util.Timer;
|
|||
import java.util.TimerTask;
|
||||
|
||||
public class RainbowName {
|
||||
private final MinecraftClient client;
|
||||
|
||||
public static final RainbowName INSTANCE = new RainbowName(MinecraftClient.getInstance());
|
||||
|
||||
private static final String BUKKIT_COLOR_CODES = "123456789abcdefklmorx";
|
||||
private static final String TEAM_NAME_CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.+";
|
||||
|
||||
private Timer timer = null;
|
||||
private final MinecraftClient client;
|
||||
private final Random random = new Random();
|
||||
|
||||
public boolean enabled = false;
|
||||
|
||||
private String[] team;
|
||||
|
||||
public String displayName;
|
||||
|
||||
private Timer timer = null;
|
||||
private String team;
|
||||
private int startHue = 0;
|
||||
|
||||
public RainbowName (final MinecraftClient client) {
|
||||
this.client = client;
|
||||
this.displayName = client.getSession().getUsername();
|
||||
}
|
||||
|
||||
public void init () {
|
||||
final TimerTask task = new TimerTask() {
|
||||
public void run () {
|
||||
|
@ -44,80 +44,36 @@ public class RainbowName {
|
|||
timer.schedule(task, 0, 50);
|
||||
}
|
||||
|
||||
private String[] generateColorCodes(int length) {
|
||||
String SALTCHARS = BUKKIT_COLOR_CODES;
|
||||
StringBuilder salt = new StringBuilder();
|
||||
Random rnd = new Random();
|
||||
while (salt.length() < length) { // length of the random string.
|
||||
int index = (int) (rnd.nextFloat() * SALTCHARS.length());
|
||||
salt.append(SALTCHARS.charAt(index));
|
||||
}
|
||||
String saltStr = salt.toString();
|
||||
return saltStr.split("");
|
||||
}
|
||||
|
||||
private String generateUsername (String[] codes) {
|
||||
StringBuilder string = new StringBuilder();
|
||||
for (String code : codes) string.append("&").append(code);
|
||||
return string.toString();
|
||||
}
|
||||
|
||||
private String generateUsername (int _codes) {
|
||||
StringBuilder string = new StringBuilder();
|
||||
|
||||
final String[] codes = generateColorCodes(_codes);
|
||||
|
||||
for (String code : codes) string.append("&").append(code);
|
||||
return string.toString();
|
||||
}
|
||||
|
||||
private String generateUsername (char[] codes, char character) {
|
||||
StringBuilder string = new StringBuilder();
|
||||
for (char code : codes) string.append(character + code);
|
||||
return string.toString();
|
||||
}
|
||||
|
||||
private String[] generateTeamName () {
|
||||
String SALTCHARS = TEAM_NAME_CHARACTERS;
|
||||
StringBuilder salt = new StringBuilder();
|
||||
Random rnd = new Random();
|
||||
while (salt.length() < TEAM_NAME_CHARACTERS.length()) { // length of the random string.
|
||||
int index = (int) (rnd.nextFloat() * SALTCHARS.length());
|
||||
salt.append(SALTCHARS.charAt(index));
|
||||
}
|
||||
String saltStr = salt.toString();
|
||||
return saltStr.split("");
|
||||
}
|
||||
|
||||
public void enable () {
|
||||
final String[] colorCodes = generateColorCodes(8);
|
||||
client.getNetworkHandler().sendChatCommand("extras:username " + generateUsername(colorCodes));
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
if (networkHandler == null) return;
|
||||
final GameProfile profile = networkHandler.getProfile();
|
||||
|
||||
team = generateTeamName();
|
||||
final String username = RandomUtilities.emptyUsername(random);
|
||||
team = RandomUtilities.randomString(random, RandomUtilities.TEAM_ALLOWED_CHARS, 16);
|
||||
final String selfSelector = UUIDUtilities.selector(profile.getId());
|
||||
|
||||
CommandCore.INSTANCE.run("minecraft:team add " + String.join("", team));
|
||||
|
||||
CommandCore.INSTANCE.run("minecraft:execute as " + client.getNetworkHandler().getProfile().getId() + " run team join " + String.join("", team));
|
||||
networkHandler.sendChatCommand("extras:username " + username);
|
||||
CommandCore.INSTANCE.run("minecraft:team add " + team);
|
||||
CommandCore.INSTANCE.run("minecraft:team join " + team + " " + selfSelector);
|
||||
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
public void disable () {
|
||||
client.getNetworkHandler().sendChatCommand("extras:username " + client.getSession().getUsername());
|
||||
|
||||
CommandCore.INSTANCE.run("minecraft:team remove " + String.join("", team));
|
||||
team = null;
|
||||
|
||||
CommandCore.INSTANCE.run("essentials:nick " + client.getSession().getUsername() + " off");
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
if (networkHandler == null) {
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
final GameProfile profile = networkHandler.getProfile();
|
||||
|
||||
CommandCore.INSTANCE.run("essentials:nick " + profile.getId() + " off");
|
||||
CommandCore.INSTANCE.run("minecraft:team remove " + team);
|
||||
networkHandler.sendChatCommand("extras:username " + profile.getName());
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
public RainbowName (MinecraftClient client) {
|
||||
this.client = client;
|
||||
this.displayName = client.getSession().getUsername();
|
||||
}
|
||||
|
||||
private void tick () {
|
||||
try {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
@ -129,25 +85,26 @@ public class RainbowName {
|
|||
|
||||
if (!enabled) return;
|
||||
|
||||
final GameProfile profile = networkHandler.getProfile();
|
||||
int hue = startHue;
|
||||
int increment = (int) (360.0 / Math.max(displayName.length(), 20));
|
||||
final int increment = (int) (360.0 / Math.max(displayName.length(), 20));
|
||||
|
||||
Component component = Component.empty();
|
||||
StringBuilder essentialsNickname = new StringBuilder();
|
||||
final StringBuilder essentialsNickname = new StringBuilder();
|
||||
|
||||
for (char character : displayName.toCharArray()) {
|
||||
String color = String.format("%06x", ColorUtilities.hsvToRgb(hue, 100, 100));
|
||||
for (final char character : displayName.toCharArray()) {
|
||||
final String color = String.format("%06x", ColorUtilities.hsvToRgb(hue, 100, 100));
|
||||
component = component.append(Component.text(character).color(TextColor.fromHexString("#" + color)));
|
||||
essentialsNickname.append("\u00a7#").append(color).append(character != ' ' ? character : '_');
|
||||
essentialsNickname.append("§#").append(color).append(character != ' ' ? character : '_');
|
||||
hue = (hue + increment) % 360;
|
||||
}
|
||||
|
||||
CommandCore.INSTANCE.run("minecraft:team modify " + String.join("", team) + " prefix " + GsonComponentSerializer.gson().serialize(component));
|
||||
CommandCore.INSTANCE.run("essentials:nick " + client.getSession().getUsername() + " " + essentialsNickname);
|
||||
CommandCore.INSTANCE.run("minecraft:team modify " + team + " prefix " + GsonComponentSerializer.gson().serialize(component));
|
||||
CommandCore.INSTANCE.run("essentials:nick " + profile.getId() + " " + essentialsNickname);
|
||||
|
||||
startHue = (startHue + increment) % 360;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} catch (final Exception e) {
|
||||
ChipmunkMod.LOGGER.error("Error while ticking rainbow name", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,161 +1,137 @@
|
|||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.GameStateChangeS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import static land.chipmunk.chipmunkmod.util.ServerUtilities.serverHasCommand;
|
||||
|
||||
public class SelfCare extends Listener {
|
||||
private final MinecraftClient client;
|
||||
public final long interval;
|
||||
public final long chatInterval;
|
||||
|
||||
public boolean opEnabled = true;
|
||||
public boolean gamemodeEnabled = true;
|
||||
public boolean cspyEnabled = true;
|
||||
public boolean icuEnabled = true;
|
||||
|
||||
private int gameMode;
|
||||
|
||||
public String skin;
|
||||
|
||||
private Timer timer;
|
||||
private Timer chatTimer;
|
||||
|
||||
private boolean cspy = false;
|
||||
public boolean hasSkin = false;
|
||||
|
||||
private int positionPacketsPerSecond = 0;
|
||||
|
||||
public static final SelfCare INSTANCE = new SelfCare(MinecraftClient.getInstance(), 70L, 500L); // make the intervals in config?
|
||||
|
||||
public SelfCare (MinecraftClient client, long interval, long chatInterval) {
|
||||
this.client = client;
|
||||
this.interval = interval;
|
||||
this.chatInterval = chatInterval;
|
||||
|
||||
this.skin = ChipmunkMod.CONFIG.autoSkinUsername == null ? "off" : ChipmunkMod.CONFIG.autoSkinUsername; // can this be null?
|
||||
|
||||
ListenerManager.addListener(this);
|
||||
}
|
||||
|
||||
public void init () {}
|
||||
|
||||
public void onJoin () {
|
||||
final TimerTask task = new TimerTask() {
|
||||
public void run () {
|
||||
tick();
|
||||
}
|
||||
};
|
||||
|
||||
final TimerTask chatTask = new TimerTask() {
|
||||
public void run () {
|
||||
chatTick();
|
||||
}
|
||||
};
|
||||
|
||||
timer = new Timer();
|
||||
chatTimer = new Timer();
|
||||
|
||||
timer.schedule(task, interval, interval);
|
||||
chatTimer.schedule(chatTask, chatInterval, chatInterval);
|
||||
}
|
||||
|
||||
public void cleanup () {
|
||||
if (timer == null || chatTimer == null) return;
|
||||
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
|
||||
chatTimer.cancel();
|
||||
chatTimer.purge();
|
||||
|
||||
gameMode = -1;
|
||||
|
||||
hasSkin = false;
|
||||
cspy = false;
|
||||
// cspy too mabe?
|
||||
// why was cspy not here lol
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chatMessageReceived (Text message) {
|
||||
final String stringMessage = message.getString();
|
||||
|
||||
if (stringMessage.equals("Successfully enabled CommandSpy")) cspy = true;
|
||||
else if (stringMessage.equals("Successfully disabled CommandSpy")) cspy = false;
|
||||
|
||||
else if (stringMessage.equals("Successfully set your skin to " + skin + "'s")) hasSkin = true;
|
||||
else if (
|
||||
stringMessage.equals("Successfully removed your skin") ||
|
||||
stringMessage.startsWith("Successfully set your skin to ")
|
||||
) hasSkin = false;
|
||||
}
|
||||
|
||||
public void tick () {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null) {
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
final ClientPlayerEntity player = client.player;
|
||||
if (player != null && !player.hasPermissionLevel(2) && opEnabled) { if (serverHasCommand("op")) networkHandler.sendChatCommand("op @s[type=player]"); }
|
||||
else if (gameMode != 1 && gamemodeEnabled) networkHandler.sendChatCommand("gamemode creative");
|
||||
else if (positionPacketsPerSecond >= 10 && icuEnabled) CommandCore.INSTANCE.run("sudo * icu stop");
|
||||
}
|
||||
|
||||
public void chatTick () {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (!cspy && cspyEnabled) { if (serverHasCommand("c")) networkHandler.sendChatCommand("c on"); }
|
||||
else if (!hasSkin && !skin.equals("off")) { if (serverHasCommand("skin")) networkHandler.sendChatCommand("skin " + skin); }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetReceived(Packet<?> packet) {
|
||||
if (packet instanceof GameJoinS2CPacket) packetReceived((GameJoinS2CPacket) packet);
|
||||
else if (packet instanceof GameStateChangeS2CPacket) packetReceived((GameStateChangeS2CPacket) packet);
|
||||
else if (packet instanceof PlayerPositionLookS2CPacket) packetReceived((PlayerPositionLookS2CPacket) packet);
|
||||
}
|
||||
|
||||
public void packetReceived(GameJoinS2CPacket packet) {
|
||||
gameMode = packet.commonPlayerSpawnInfo().gameMode().getId();
|
||||
}
|
||||
|
||||
public void packetReceived(GameStateChangeS2CPacket packet) {
|
||||
if (packet.getReason() != GameStateChangeS2CPacket.GAME_MODE_CHANGED) return;
|
||||
|
||||
gameMode = (int) packet.getValue();
|
||||
}
|
||||
|
||||
public void packetReceived(PlayerPositionLookS2CPacket packet) {
|
||||
if (timer == null) return;
|
||||
|
||||
try {
|
||||
positionPacketsPerSecond++;
|
||||
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
positionPacketsPerSecond--;
|
||||
}
|
||||
}, 1000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.GameStateChangeS2CPacket;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import static land.chipmunk.chipmunkmod.util.ServerUtilities.serverHasCommand;
|
||||
|
||||
public class SelfCare implements Listener {
|
||||
public static final SelfCare INSTANCE = new SelfCare(MinecraftClient.getInstance(), 70L, 500L); // make the intervals in config?
|
||||
public final long interval;
|
||||
public final long chatInterval;
|
||||
private final MinecraftClient client;
|
||||
public boolean opEnabled = ChipmunkMod.CONFIG.selfCare.op;
|
||||
public boolean gamemodeEnabled = ChipmunkMod.CONFIG.selfCare.gameMode;
|
||||
public boolean cspyEnabled = ChipmunkMod.CONFIG.selfCare.cspy;
|
||||
public String skin;
|
||||
public boolean hasSkin = false;
|
||||
private int gameMode;
|
||||
private Timer timer;
|
||||
private Timer chatTimer;
|
||||
private boolean cspy = false;
|
||||
|
||||
public SelfCare (final MinecraftClient client, final long interval, final long chatInterval) {
|
||||
this.client = client;
|
||||
this.interval = interval;
|
||||
this.chatInterval = chatInterval;
|
||||
|
||||
this.skin = ChipmunkMod.CONFIG.autoSkinUsername == null ? "off" : ChipmunkMod.CONFIG.autoSkinUsername; // can this be null?
|
||||
|
||||
ListenerManager.addListener(this);
|
||||
}
|
||||
|
||||
public void init () {
|
||||
}
|
||||
|
||||
public void onJoin () {
|
||||
final TimerTask task = new TimerTask() {
|
||||
public void run () {
|
||||
tick();
|
||||
}
|
||||
};
|
||||
|
||||
final TimerTask chatTask = new TimerTask() {
|
||||
public void run () {
|
||||
chatTick();
|
||||
}
|
||||
};
|
||||
|
||||
timer = new Timer();
|
||||
chatTimer = new Timer();
|
||||
|
||||
timer.schedule(task, interval, interval);
|
||||
chatTimer.schedule(chatTask, chatInterval, chatInterval);
|
||||
}
|
||||
|
||||
public void cleanup () {
|
||||
if (timer == null || chatTimer == null) return;
|
||||
|
||||
timer.cancel();
|
||||
timer.purge();
|
||||
|
||||
chatTimer.cancel();
|
||||
chatTimer.purge();
|
||||
|
||||
gameMode = -1;
|
||||
|
||||
hasSkin = false;
|
||||
cspy = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chatMessageReceived (final Text message) {
|
||||
final String stringMessage = message.getString();
|
||||
|
||||
if (stringMessage.equals("Successfully enabled CommandSpy")) cspy = true;
|
||||
else if (stringMessage.equals("Successfully disabled CommandSpy")) cspy = false;
|
||||
|
||||
else if (stringMessage.equals("Successfully set your skin to " + skin + "'s")) hasSkin = true;
|
||||
else if (
|
||||
stringMessage.equals("Successfully removed your skin") ||
|
||||
stringMessage.startsWith("Successfully set your skin to ")
|
||||
) hasSkin = false;
|
||||
}
|
||||
|
||||
public void tick () {
|
||||
final ClientPlayerEntity player = client.player;
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null) {
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
if (player != null && !player.hasPermissionLevel(2) && opEnabled && serverHasCommand("op"))
|
||||
networkHandler.sendChatCommand("op @s[type=player]");
|
||||
else if (gameMode != 1 && gamemodeEnabled) networkHandler.sendChatCommand("gamemode creative");
|
||||
}
|
||||
|
||||
public void chatTick () {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null) return;
|
||||
|
||||
if (!cspy && cspyEnabled) {
|
||||
if (serverHasCommand("c")) networkHandler.sendChatCommand("c on");
|
||||
} else if (!hasSkin && !skin.equals("off")) {
|
||||
if (serverHasCommand("skin")) networkHandler.sendChatCommand("skin " + skin);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetReceived (final Packet<?> packet) {
|
||||
if (packet instanceof GameJoinS2CPacket) packetReceived((GameJoinS2CPacket) packet);
|
||||
else if (packet instanceof GameStateChangeS2CPacket) packetReceived((GameStateChangeS2CPacket) packet);
|
||||
}
|
||||
|
||||
public void packetReceived (final GameJoinS2CPacket packet) {
|
||||
gameMode = packet.commonPlayerSpawnInfo().gameMode().getId();
|
||||
}
|
||||
|
||||
public void packetReceived (final GameStateChangeS2CPacket packet) {
|
||||
if (packet.getReason() != GameStateChangeS2CPacket.GAME_MODE_CHANGED) return;
|
||||
|
||||
gameMode = (int) packet.getValue();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,16 @@ import land.chipmunk.chipmunkmod.song.Song;
|
|||
import land.chipmunk.chipmunkmod.song.SongLoaderException;
|
||||
import land.chipmunk.chipmunkmod.song.SongLoaderThread;
|
||||
import land.chipmunk.chipmunkmod.util.MathUtilities;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -25,65 +25,71 @@ import java.util.Timer;
|
|||
import java.util.TimerTask;
|
||||
|
||||
public class SongPlayer {
|
||||
public static final String SELECTOR = "@a[tag=!nomusic,tag=!chipmunkmod_nomusic]";
|
||||
public static final String SELECTOR = "@a[tag=cm_name3_music,tag=!nomusic,tag=!chipmunkmod_nomusic]";
|
||||
public static final SongPlayer INSTANCE = new SongPlayer(MinecraftClient.getInstance());
|
||||
public static File SONG_DIR = new File("songs");
|
||||
|
||||
static {
|
||||
if (!SONG_DIR.exists()) {
|
||||
SONG_DIR.mkdir();
|
||||
}
|
||||
}
|
||||
|
||||
public static final SongPlayer INSTANCE = new SongPlayer(MinecraftClient.getInstance());
|
||||
|
||||
private final MinecraftClient client;
|
||||
public Song currentSong;
|
||||
public LinkedList<Song> songQueue = new LinkedList<>();
|
||||
public Timer playTimer;
|
||||
public SongLoaderThread loaderThread;
|
||||
private int ticksUntilPausedActionbar = 20;
|
||||
|
||||
public boolean useCore = true;
|
||||
public boolean actionbar = true;
|
||||
|
||||
public float pitch = 0;
|
||||
private int ticksUntilPausedActionbar = 20;
|
||||
|
||||
private final MinecraftClient client;
|
||||
|
||||
public SongPlayer (MinecraftClient client) {
|
||||
public SongPlayer (final MinecraftClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
// TODO: Less duplicate code
|
||||
|
||||
public void loadSong (Path location) {
|
||||
public void loadSong (final Path location) {
|
||||
final ClientPlayerEntity player = client.player;
|
||||
|
||||
if (player == null) return;
|
||||
|
||||
if (loaderThread != null) {
|
||||
((Audience) client.player).sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED));
|
||||
player.sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final SongLoaderThread _loaderThread = new SongLoaderThread(location);
|
||||
((Audience) client.player).sendMessage(Component.translatable("Loading %s", Component.text(location.getFileName().toString(), NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN));
|
||||
player.sendMessage(Component.translatable("Loading %s", Component.text(location.toString(), TextColor.fromHexString("#ffccee"))).color(TextColor.fromHexString("#ff99dd")));
|
||||
_loaderThread.start();
|
||||
loaderThread = _loaderThread;
|
||||
} catch (SongLoaderException e) {
|
||||
((Audience) client.player).sendMessage(Component.translatable("Failed to load song: %s", e.message.getString()).color(NamedTextColor.RED));
|
||||
} catch (final SongLoaderException e) {
|
||||
player.sendMessage(Component.translatable("Failed to load song: %s", Component.text(e.message.getString())).color(NamedTextColor.RED));
|
||||
loaderThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void loadSong (URL location) {
|
||||
public void loadSong (final URL location) {
|
||||
final ClientPlayerEntity player = client.player;
|
||||
|
||||
if (player == null) return;
|
||||
|
||||
if (loaderThread != null) {
|
||||
((Audience) client.player).sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED));
|
||||
player.sendMessage(Component.translatable("Already loading a song, cannot load another", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final SongLoaderThread _loaderThread = new SongLoaderThread(location);
|
||||
((Audience) client.player).sendMessage(Component.translatable("Loading %s", Component.text(location.toString(), NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN));
|
||||
player.sendMessage(Component.translatable("Loading %s", Component.text(location.toString(), TextColor.fromHexString("#ffccee"))).color(TextColor.fromHexString("#ff99dd")));
|
||||
_loaderThread.start();
|
||||
loaderThread = _loaderThread;
|
||||
} catch (SongLoaderException e) {
|
||||
((Audience) client.player).sendMessage(Component.translatable("Failed to load song: %s", e.message.getString()).color(NamedTextColor.RED));
|
||||
} catch (final SongLoaderException e) {
|
||||
player.sendMessage(Component.translatable("Failed to load song: %s", Component.text(e.message.getString())).color(NamedTextColor.RED));
|
||||
loaderThread = null;
|
||||
}
|
||||
}
|
||||
|
@ -101,12 +107,12 @@ public class SongPlayer {
|
|||
return;
|
||||
}
|
||||
|
||||
if (loaderThread != null && !loaderThread.isAlive()) {
|
||||
if (loaderThread != null && !loaderThread.isAlive() && client.player != null) {
|
||||
if (loaderThread.exception != null) {
|
||||
((Audience) client.player).sendMessage(Component.translatable("Failed to load song: %s", loaderThread.exception.message.getString()).color(NamedTextColor.RED));
|
||||
client.player.sendMessage(Component.translatable("Failed to load song: %s", Component.text(loaderThread.exception.message.getString())).color(NamedTextColor.RED));
|
||||
} else {
|
||||
songQueue.add(loaderThread.song);
|
||||
((Audience) client.player).sendMessage(Component.translatable("Added %s to the song queue", Component.empty().append(loaderThread.song.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN));
|
||||
client.player.sendMessage(Component.translatable("Added %s to the song queue", Component.empty().append(loaderThread.song.name).color(TextColor.fromHexString("#ffccee"))).color(TextColor.fromHexString("#ff99dd")));
|
||||
}
|
||||
loaderThread = null;
|
||||
}
|
||||
|
@ -114,8 +120,19 @@ public class SongPlayer {
|
|||
if (currentSong == null) {
|
||||
if (songQueue.isEmpty()) return;
|
||||
|
||||
CommandCore.INSTANCE.run("tag " + MinecraftClient.getInstance().getSession().getUsername() + " add cm_name3_music");
|
||||
|
||||
currentSong = songQueue.poll();
|
||||
((Audience) client.player).sendMessage(Component.translatable("Now playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN));
|
||||
if (client.player != null) client.player.sendMessage(
|
||||
Component
|
||||
.translatable(
|
||||
"Now playing %s",
|
||||
Component.empty()
|
||||
.append(currentSong.name)
|
||||
.color(TextColor.fromHexString("#ffccee"))
|
||||
)
|
||||
.color(TextColor.fromHexString("#ff99dd"))
|
||||
);
|
||||
currentSong.play();
|
||||
}
|
||||
|
||||
|
@ -123,9 +140,11 @@ public class SongPlayer {
|
|||
else ticksUntilPausedActionbar = 20;
|
||||
|
||||
try {
|
||||
if (!useCore && actionbar && client.player != null) ((Audience) client.player).sendActionBar(generateActionbar());
|
||||
else if (actionbar) CommandCore.INSTANCE.run("title " + SELECTOR + " actionbar " + GsonComponentSerializer.gson().serialize(generateActionbar()));
|
||||
} catch (Exception e) {
|
||||
if (!useCore && actionbar && client.player != null)
|
||||
client.player.sendActionBar(generateActionbar());
|
||||
else if (actionbar)
|
||||
CommandCore.INSTANCE.run("title " + SELECTOR + " actionbar " + GsonComponentSerializer.gson().serialize(generateActionbar()));
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
@ -134,7 +153,8 @@ public class SongPlayer {
|
|||
handlePlaying();
|
||||
|
||||
if (currentSong.finished()) {
|
||||
((Audience) client.player).sendMessage(Component.translatable("Finished playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN));
|
||||
if (client.player != null)
|
||||
client.player.sendMessage(Component.translatable("Finished playing %s", Component.empty().append(currentSong.name).color(TextColor.fromHexString("#ffccee"))).color(TextColor.fromHexString("#ff99dd")));
|
||||
currentSong = null;
|
||||
}
|
||||
}
|
||||
|
@ -148,37 +168,37 @@ public class SongPlayer {
|
|||
public Component generateActionbar () {
|
||||
final ClientPlayerEntity player = client.player;
|
||||
|
||||
Component component = Component.empty()
|
||||
.append(Component.translatable("%s", player.getName().getString()).color(NamedTextColor.GREEN))
|
||||
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
|
||||
.append(Component.translatable("Now playing %s", Component.empty().append(currentSong.name).color(NamedTextColor.DARK_GREEN)).color(NamedTextColor.GREEN))
|
||||
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
|
||||
.append(Component.translatable("%s / %s", formatTime(currentSong.time).color(NamedTextColor.GREEN), formatTime(currentSong.length).color(NamedTextColor.GREEN)).color(NamedTextColor.GRAY))
|
||||
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
|
||||
.append(Component.translatable("%s / %s", Component.text(currentSong.position, NamedTextColor.GREEN), Component.text(currentSong.size(), NamedTextColor.GREEN)).color(NamedTextColor.GRAY));
|
||||
final Component component = Component.empty()
|
||||
.append(Component.translatable("%s", player.getName().getString()).color(TextColor.fromHexString("#ff99dd")))
|
||||
.append(Component.translatable(" | ", NamedTextColor.WHITE))
|
||||
.append(Component.translatable("Now playing %s", Component.empty().append(currentSong.name).color(TextColor.fromHexString("#ffccee"))).color(TextColor.fromHexString("#ff99dd")))
|
||||
.append(Component.translatable(" | ", NamedTextColor.WHITE))
|
||||
.append(Component.translatable("%s / %s", formatTime(currentSong.time).color(TextColor.fromHexString("#ff99dd")), formatTime(currentSong.length).color(TextColor.fromHexString("#ff99dd"))).color(NamedTextColor.WHITE))
|
||||
.append(Component.translatable(" | ", NamedTextColor.WHITE))
|
||||
.append(Component.translatable("%s / %s", Component.text(currentSong.position, TextColor.fromHexString("#ff99dd")), Component.text(currentSong.size(), TextColor.fromHexString("#ff99dd"))).color(NamedTextColor.WHITE));
|
||||
|
||||
if (currentSong.paused) {
|
||||
return component
|
||||
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
|
||||
.append(Component.translatable("Paused", NamedTextColor.DARK_GREEN));
|
||||
.append(Component.translatable(" | ", NamedTextColor.WHITE))
|
||||
.append(Component.translatable("Paused", TextColor.fromHexString("#ffccee")));
|
||||
}
|
||||
|
||||
if (currentSong.looping) {
|
||||
if (currentSong.loopCount > 0) {
|
||||
return component
|
||||
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
|
||||
.append(Component.translatable("Looping (%s/%s)", Component.text(currentSong.currentLoop), Component.text(currentSong.loopCount)).color(NamedTextColor.DARK_GREEN));
|
||||
.append(Component.translatable(" | ", NamedTextColor.WHITE))
|
||||
.append(Component.translatable("Looping (%s/%s)", Component.text(currentSong.currentLoop), Component.text(currentSong.loopCount)).color(TextColor.fromHexString("#ffccee")));
|
||||
}
|
||||
|
||||
return component
|
||||
.append(Component.translatable(" | ", NamedTextColor.DARK_GRAY))
|
||||
.append(Component.translatable("Looping", NamedTextColor.DARK_GREEN));
|
||||
.append(Component.translatable(" | ", NamedTextColor.WHITE))
|
||||
.append(Component.translatable("Looping", TextColor.fromHexString("#ffccee")));
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
public Component formatTime (long millis) {
|
||||
public Component formatTime (final long millis) {
|
||||
final int seconds = (int) millis / 1000;
|
||||
|
||||
final String minutePart = String.valueOf(seconds / 60);
|
||||
|
@ -211,26 +231,39 @@ public class SongPlayer {
|
|||
if (!useCore && client.player != null) {
|
||||
final float floatingPitch = (float) (0.5 * (Math.pow(2, ((note.pitch + (pitch / 10)) / 12))));
|
||||
|
||||
final String[] thing = note.instrument.sound.split(":");
|
||||
|
||||
if (thing[1] == null) return; // idk if this can be null but ill just protect it for now i guess
|
||||
final String sound = note.instrument.sound;
|
||||
|
||||
client.submit(() -> client.world.playSound(
|
||||
client.player.getX(),
|
||||
client.player.getY(),
|
||||
client.player.getZ(),
|
||||
SoundEvent.of(Identifier.of(thing[0], thing[1])),
|
||||
client.player.getX() + note.position.getX(),
|
||||
client.player.getY() + note.position.getY(),
|
||||
client.player.getZ() + note.position.getZ(),
|
||||
SoundEvent.of(Identifier.of(Key.MINECRAFT_NAMESPACE, sound)),
|
||||
SoundCategory.RECORDS,
|
||||
note.volume,
|
||||
floatingPitch,
|
||||
true
|
||||
));
|
||||
} else {
|
||||
final float floatingPitch = MathUtilities.clamp((float) (0.5 * (Math.pow(2, ((note.pitch + (pitch / 10)) / 12)))), 0F, 2F);
|
||||
final double floatingPitch = MathUtilities.clamp(0.5 * (Math.pow(2, ((note.pitch + (pitch / 10)) / 12))), 0F, 2F);
|
||||
|
||||
CommandCore.INSTANCE.run("execute as " + SELECTOR + " at @s run playsound " + note.instrument.sound + " record @s ~ ~ ~ " + note.volume + " " + floatingPitch);
|
||||
CommandCore.INSTANCE.run(
|
||||
String.format(
|
||||
"execute as %s at @s run playsound %s record @s ^%f ^%f ^%f %f %f",
|
||||
|
||||
SELECTOR,
|
||||
|
||||
note.instrument.sound,
|
||||
|
||||
note.position.getX(),
|
||||
note.position.getY(),
|
||||
note.position.getZ(),
|
||||
|
||||
note.volume,
|
||||
floatingPitch
|
||||
)
|
||||
);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
import land.chipmunk.chipmunkmod.listeners.Listener;
|
||||
import land.chipmunk.chipmunkmod.listeners.ListenerManager;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.c2s.play.RequestCommandCompletionsC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.play.CommandSuggestionsS2CPacket;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class TabComplete extends Listener {
|
||||
private final MinecraftClient client;
|
||||
|
||||
private final Map<Integer, CompletableFuture<CommandSuggestionsS2CPacket>> transactions = new HashMap<>();
|
||||
|
||||
public static TabComplete INSTANCE = new TabComplete(MinecraftClient.getInstance());
|
||||
|
||||
public TabComplete (MinecraftClient client) {
|
||||
this.client = client;
|
||||
ListenerManager.addListener(this);
|
||||
}
|
||||
|
||||
public void init () {}
|
||||
|
||||
public CompletableFuture<CommandSuggestionsS2CPacket> complete (String command) {
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
if (networkHandler == null) return null;
|
||||
|
||||
final ClientConnection connection = networkHandler.getConnection();
|
||||
|
||||
if (connection == null) return null;
|
||||
|
||||
final int transactionId = TransactionManager.INSTANCE.nextTransactionId();
|
||||
connection.send(new RequestCommandCompletionsC2SPacket(transactionId, command));
|
||||
|
||||
final CompletableFuture<CommandSuggestionsS2CPacket> future = new CompletableFuture<>();
|
||||
transactions.put(transactionId, future);
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packetReceived (Packet<?> packet) {
|
||||
if (packet instanceof CommandSuggestionsS2CPacket) packetReceived((CommandSuggestionsS2CPacket) packet);
|
||||
}
|
||||
|
||||
public void packetReceived (CommandSuggestionsS2CPacket packet) {
|
||||
final CompletableFuture<CommandSuggestionsS2CPacket> future = transactions.get(packet.id());
|
||||
|
||||
if (future == null) return;
|
||||
future.complete(packet);
|
||||
transactions.remove(future);
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.modules;
|
||||
|
||||
public class TransactionManager {
|
||||
public static final TransactionManager INSTANCE = new TransactionManager();
|
||||
|
||||
private int transactionId = 0;
|
||||
|
||||
public int transactionId () { return transactionId; }
|
||||
|
||||
public int nextTransactionId () { return transactionId++; }
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package land.chipmunk.chipmunkmod.modules.custom_chat;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.modules.Chat;
|
||||
import land.chipmunk.chipmunkmod.modules.CommandCore;
|
||||
import land.chipmunk.chipmunkmod.modules.KaboomCheck;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CustomChat {
|
||||
public static final CustomChat INSTANCE = new CustomChat(MinecraftClient.getInstance());
|
||||
|
||||
private static final GsonComponentSerializer GSON = GsonComponentSerializer.gson();
|
||||
private static final CustomChatComponentRenderer RENDERER = new CustomChatComponentRenderer();
|
||||
private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer
|
||||
|
||||
// https://sus.red/abc?a=b&c=d will still break the click events, though
|
||||
.legacyAmpersand()
|
||||
|
||||
.toBuilder()
|
||||
|
||||
.extractUrls(
|
||||
Pattern
|
||||
.compile("((https?://(ww(w|\\d)\\.)?|ww(w|\\d))[-a-zA-Z0-9@:%._+~#=]{1,256}"
|
||||
+ "\\.[a-zA-Z0-9]{1,63}\\b([-a-zA-Z0-9@:%_+.~#?&/=]*))"),
|
||||
Style.style(
|
||||
NamedTextColor.BLUE,
|
||||
TextDecoration.UNDERLINED,
|
||||
HoverEvent.showText(
|
||||
Component
|
||||
.text("Click here to open the URL")
|
||||
.color(NamedTextColor.BLUE)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// > `this.useTerriblyStupidHexFormat = true`
|
||||
// i know it is stupid indeed,
|
||||
// but i also want the compatibility to the kaboom chat
|
||||
.useUnusualXRepeatedCharacterHexFormat() // &x&1&2&3&4&5&6abc
|
||||
|
||||
.build();
|
||||
|
||||
private final MinecraftClient client;
|
||||
public boolean enabled = true;
|
||||
|
||||
public Component format = ChipmunkMod.CONFIG.customChat.format;
|
||||
|
||||
public CustomChat (final MinecraftClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public void chat (final String message) {
|
||||
final ClientPlayerEntity player = client.player;
|
||||
if (player == null) return;
|
||||
if (!enabled || !player.hasPermissionLevel(2) || !player.isCreative()) {
|
||||
Chat.sendChatMessage(message, true);
|
||||
return;
|
||||
}
|
||||
|
||||
final Component styledMessage = SERIALIZER.deserialize(message);
|
||||
|
||||
final String username = MinecraftClient.getInstance().getSession().getUsername();
|
||||
|
||||
final CustomChatContext context = new CustomChatContext(player.getUuidAsString(), styledMessage,
|
||||
Map.of("MESSAGE", message, "USERNAME", username));
|
||||
final Component renderedFormat = RENDERER.render(format, context)
|
||||
.compact();
|
||||
final String json = GSON.serialize(renderedFormat);
|
||||
|
||||
CommandCore.INSTANCE.run((KaboomCheck.INSTANCE.isKaboom ? "minecraft:tellraw @a " : "tellraw @a ") + json);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package land.chipmunk.chipmunkmod.modules.custom_chat;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentBuilder;
|
||||
import net.kyori.adventure.text.SelectorComponent;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.renderer.TranslatableComponentRenderer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// We don't do any translatable rendering here, but extending from that makes it easier to work with.
|
||||
public final class CustomChatComponentRenderer extends TranslatableComponentRenderer<CustomChatContext> {
|
||||
@Override
|
||||
protected @NotNull Component renderSelector (final @NotNull SelectorComponent component,
|
||||
final @NotNull CustomChatContext context) {
|
||||
final String pattern = component.pattern();
|
||||
if (pattern.equals("@s")) {
|
||||
final SelectorComponent.Builder builder = Component.selector()
|
||||
.pattern(context.uuid());
|
||||
|
||||
return this.mergeStyleAndOptionallyDeepRender(component, builder, context);
|
||||
}
|
||||
|
||||
return super.renderSelector(component, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull Component renderText (final @NotNull TextComponent component,
|
||||
final @NotNull CustomChatContext context) {
|
||||
final String content = component.content();
|
||||
if (content.equals("MESSAGE")) {
|
||||
return this.mergeMessage(component, context.message(), context);
|
||||
}
|
||||
|
||||
final String arg = context.args().get(component.content());
|
||||
if (arg != null) {
|
||||
final TextComponent.Builder builder = Component.text()
|
||||
.content(arg);
|
||||
|
||||
return this.mergeStyleAndOptionallyDeepRender(component, builder, context);
|
||||
}
|
||||
|
||||
return super.renderText(component, context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NonExtendableApiUsage") // we're not extending it silly
|
||||
@Override
|
||||
protected <B extends ComponentBuilder<?, ?>> void mergeStyle (final Component component, final B builder,
|
||||
final CustomChatContext context) {
|
||||
super.mergeStyle(component, builder, context);
|
||||
|
||||
// render clickEvent that may contain something like "MESSAGE"
|
||||
// HoverEvent already handled by super
|
||||
builder.clickEvent(this.mergeClickEvent(component.clickEvent(), context));
|
||||
}
|
||||
|
||||
private Component mergeMessage (final Component root, final Component msg, final CustomChatContext context) {
|
||||
Component result = msg.applyFallbackStyle(root.style()); // applyFallbackStyle will apply everything that isn't content
|
||||
|
||||
final ClickEvent clickEvent = result.clickEvent();
|
||||
if (clickEvent != null) {
|
||||
result = result.clickEvent(mergeClickEvent(clickEvent, context));
|
||||
}
|
||||
|
||||
final HoverEvent<?> hoverEvent = result.hoverEvent();
|
||||
if (hoverEvent != null) {
|
||||
result = result.hoverEvent(hoverEvent.withRenderedValue(this, context));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private ClickEvent mergeClickEvent (final ClickEvent clickEvent, final CustomChatContext context) {
|
||||
if (clickEvent == null) return null;
|
||||
|
||||
final String value = clickEvent.value();
|
||||
final String arg = context.args().get(value);
|
||||
if (arg == null) return clickEvent;
|
||||
|
||||
return ClickEvent.clickEvent(clickEvent.action(), arg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package land.chipmunk.chipmunkmod.modules.custom_chat;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record CustomChatContext(String uuid, Component message, Map<String, String> args) {
|
||||
}
|
|
@ -1,48 +1,47 @@
|
|||
package land.chipmunk.chipmunkmod.song;
|
||||
|
||||
public class Instrument {
|
||||
public static final Instrument HARP = new Instrument(0, "harp", 54);
|
||||
public static final Instrument BASEDRUM = new Instrument(1, "basedrum", 0);
|
||||
public static final Instrument SNARE = new Instrument(2, "snare", 0);
|
||||
public static final Instrument HAT = new Instrument(3, "hat", 0);
|
||||
public static final Instrument BASS = new Instrument(4, "bass", 30);
|
||||
public static final Instrument FLUTE = new Instrument(5, "flute", 66);
|
||||
public static final Instrument BELL = new Instrument(6, "bell", 78);
|
||||
public static final Instrument GUITAR = new Instrument(7, "guitar", 42);
|
||||
public static final Instrument CHIME = new Instrument(8, "chime", 78);
|
||||
public static final Instrument XYLOPHONE = new Instrument(9, "xylophone", 78);
|
||||
public static final Instrument IRON_XYLOPHONE = new Instrument(10, "iron_xylophone", 54);
|
||||
public static final Instrument COW_BELL = new Instrument(11, "cow_bell", 66);
|
||||
public static final Instrument DIDGERIDOO = new Instrument(12, "didgeridoo", 30);
|
||||
public static final Instrument BIT = new Instrument(13, "bit", 54);
|
||||
public static final Instrument BANJO = new Instrument(14, "banjo", 54);
|
||||
public static final Instrument PLING = new Instrument(15, "pling", 54);
|
||||
public static final Instrument HARP = new Instrument(0, "harp", 54);
|
||||
public static final Instrument BASEDRUM = new Instrument(1, "basedrum", 0);
|
||||
public static final Instrument SNARE = new Instrument(2, "snare", 0);
|
||||
public static final Instrument HAT = new Instrument(3, "hat", 0);
|
||||
public static final Instrument BASS = new Instrument(4, "bass", 30);
|
||||
public static final Instrument FLUTE = new Instrument(5, "flute", 66);
|
||||
public static final Instrument BELL = new Instrument(6, "bell", 78);
|
||||
public static final Instrument GUITAR = new Instrument(7, "guitar", 42);
|
||||
public static final Instrument CHIME = new Instrument(8, "chime", 78);
|
||||
public static final Instrument XYLOPHONE = new Instrument(9, "xylophone", 78);
|
||||
public static final Instrument IRON_XYLOPHONE = new Instrument(10, "iron_xylophone", 54);
|
||||
public static final Instrument COW_BELL = new Instrument(11, "cow_bell", 66);
|
||||
public static final Instrument DIDGERIDOO = new Instrument(12, "didgeridoo", 30);
|
||||
public static final Instrument BIT = new Instrument(13, "bit", 54);
|
||||
public static final Instrument BANJO = new Instrument(14, "banjo", 54);
|
||||
public static final Instrument PLING = new Instrument(15, "pling", 54);
|
||||
private static final Instrument[] VALUES = { HARP, BASEDRUM, SNARE, HAT, BASS, FLUTE, BELL, GUITAR, CHIME, XYLOPHONE, IRON_XYLOPHONE, COW_BELL, DIDGERIDOO, BIT, BANJO, PLING };
|
||||
public final int id;
|
||||
public final String name;
|
||||
public final int offset;
|
||||
public final String sound;
|
||||
|
||||
public final int id;
|
||||
public final String name;
|
||||
public final int offset;
|
||||
public final String sound;
|
||||
private Instrument (final int id, final String name, final int offset, final String sound) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
this.sound = sound;
|
||||
}
|
||||
|
||||
private Instrument (int id, String name, int offset, String sound) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
this.sound = sound;
|
||||
}
|
||||
private Instrument (final int id, final String name, final int offset) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
this.sound = "block.note_block." + name;
|
||||
}
|
||||
|
||||
private Instrument (int id, String name, int offset) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
this.sound = "minecraft:block.note_block." + name;
|
||||
}
|
||||
public static Instrument of (final String sound) {
|
||||
return new Instrument(-1, null, 0, sound);
|
||||
}
|
||||
|
||||
public static Instrument of (String sound) {
|
||||
return new Instrument(-1, null, 0, sound);
|
||||
}
|
||||
|
||||
private static Instrument[] values = {HARP, BASEDRUM, SNARE, HAT, BASS, FLUTE, BELL, GUITAR, CHIME, XYLOPHONE, IRON_XYLOPHONE, COW_BELL, DIDGERIDOO, BIT, BANJO, PLING};
|
||||
public static Instrument fromId (int id) {
|
||||
return values[id];
|
||||
}
|
||||
public static Instrument fromId (final int id) {
|
||||
return VALUES[id];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
package land.chipmunk.chipmunkmod.song;
|
||||
|
||||
import land.chipmunk.chipmunkmod.util.DownloadUtilities;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
@ -10,364 +16,357 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.sound.midi.*;
|
||||
|
||||
public class MidiConverter {
|
||||
public static final int SET_INSTRUMENT = 0xC0;
|
||||
public static final int SET_TEMPO = 0x51;
|
||||
public static final int NOTE_ON = 0x90;
|
||||
public static final int NOTE_OFF = 0x80;
|
||||
public static final int SET_INSTRUMENT = 0xC0;
|
||||
public static final int SET_TEMPO = 0x51;
|
||||
public static final int NOTE_ON = 0x90;
|
||||
public static final int NOTE_OFF = 0x80;
|
||||
public static HashMap<Integer, Instrument[]> instrumentMap = new HashMap<>();
|
||||
public static HashMap<Integer, Integer> percussionMap = new HashMap<>();
|
||||
|
||||
public static Song getSongFromUrl(URL url) throws IOException, InvalidMidiDataException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
|
||||
Sequence sequence = MidiSystem.getSequence(DownloadUtilities.DownloadToInputStream(url));
|
||||
return getSong(sequence, Paths.get(url.toURI().getPath()).getFileName().toString());
|
||||
}
|
||||
static {
|
||||
// Piano (HARP BASS BELL)
|
||||
instrumentMap.put(0, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Acoustic Grand Piano
|
||||
instrumentMap.put(1, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Bright Acoustic Piano
|
||||
instrumentMap.put(2, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL }); // Electric Grand Piano
|
||||
instrumentMap.put(3, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Honky-tonk Piano
|
||||
instrumentMap.put(4, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL }); // Electric Piano 1
|
||||
instrumentMap.put(5, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL }); // Electric Piano 2
|
||||
instrumentMap.put(6, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Harpsichord
|
||||
instrumentMap.put(7, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Clavinet
|
||||
|
||||
public static Song getSongFromFile(File file) throws InvalidMidiDataException, IOException {
|
||||
Sequence sequence = MidiSystem.getSequence(file);
|
||||
return getSong(sequence, file.getName());
|
||||
}
|
||||
// Chromatic Percussion (IRON_XYLOPHONE XYLOPHONE BASS)
|
||||
instrumentMap.put(8, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Celesta
|
||||
instrumentMap.put(9, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Glockenspiel
|
||||
instrumentMap.put(10, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Music Box
|
||||
instrumentMap.put(11, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Vibraphone
|
||||
instrumentMap.put(12, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Marimba
|
||||
instrumentMap.put(13, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Xylophone
|
||||
instrumentMap.put(14, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Tubular Bells
|
||||
instrumentMap.put(15, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE }); // Dulcimer
|
||||
|
||||
public static Song getSongFromBytes(byte[] bytes, String name) throws InvalidMidiDataException, IOException {
|
||||
Sequence sequence = MidiSystem.getSequence(new ByteArrayInputStream(bytes));
|
||||
return getSong(sequence, name);
|
||||
}
|
||||
|
||||
public static Song getSong(Sequence sequence, String name) {
|
||||
Song song = new Song(name);
|
||||
// Organ (BIT DIDGERIDOO BELL)
|
||||
instrumentMap.put(16, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Drawbar Organ
|
||||
instrumentMap.put(17, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Percussive Organ
|
||||
instrumentMap.put(18, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Rock Organ
|
||||
instrumentMap.put(19, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Church Organ
|
||||
instrumentMap.put(20, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Reed Organ
|
||||
instrumentMap.put(21, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Accordian
|
||||
instrumentMap.put(22, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Harmonica
|
||||
instrumentMap.put(23, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Tango Accordian
|
||||
|
||||
long tpq = sequence.getResolution();
|
||||
// Guitar (BIT DIDGERIDOO BELL)
|
||||
instrumentMap.put(24, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Acoustic Guitar (nylon)
|
||||
instrumentMap.put(25, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Acoustic Guitar (steel)
|
||||
instrumentMap.put(26, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Electric Guitar (jazz)
|
||||
instrumentMap.put(27, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Electric Guitar (clean)
|
||||
instrumentMap.put(28, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Electric Guitar (muted)
|
||||
instrumentMap.put(29, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Overdriven Guitar
|
||||
instrumentMap.put(30, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Distortion Guitar
|
||||
instrumentMap.put(31, new Instrument[] { Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Guitar Harmonics
|
||||
|
||||
ArrayList<MidiEvent> tempoEvents = new ArrayList<>();
|
||||
for (Track track : sequence.getTracks()) {
|
||||
for (int i = 0; i < track.size(); i++) {
|
||||
MidiEvent event = track.get(i);
|
||||
MidiMessage message = event.getMessage();
|
||||
if (message instanceof MetaMessage) {
|
||||
MetaMessage mm = (MetaMessage) message;
|
||||
if (mm.getType() == SET_TEMPO) {
|
||||
tempoEvents.add(event);
|
||||
}
|
||||
// Bass
|
||||
instrumentMap.put(32, new Instrument[] { Instrument.BASS, Instrument.HARP, Instrument.BELL }); // Acoustic Bass
|
||||
instrumentMap.put(33, new Instrument[] { Instrument.BASS, Instrument.HARP, Instrument.BELL }); // Electric Bass (finger)
|
||||
instrumentMap.put(34, new Instrument[] { Instrument.BASS, Instrument.HARP, Instrument.BELL }); // Electric Bass (pick)
|
||||
instrumentMap.put(35, new Instrument[] { Instrument.BASS, Instrument.HARP, Instrument.BELL }); // Fretless Bass
|
||||
instrumentMap.put(36, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Slap Bass 1
|
||||
instrumentMap.put(37, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Slap Bass 2
|
||||
instrumentMap.put(38, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Synth Bass 1
|
||||
instrumentMap.put(39, new Instrument[] { Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE }); // Synth Bass 2
|
||||
|
||||
// Strings
|
||||
instrumentMap.put(40, new Instrument[] { Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL }); // Violin
|
||||
instrumentMap.put(41, new Instrument[] { Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL }); // Viola
|
||||
instrumentMap.put(42, new Instrument[] { Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL }); // Cello
|
||||
instrumentMap.put(43, new Instrument[] { Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL }); // Contrabass
|
||||
instrumentMap.put(44, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL }); // Tremolo Strings
|
||||
instrumentMap.put(45, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Pizzicato Strings
|
||||
instrumentMap.put(46, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.CHIME }); // Orchestral Harp
|
||||
instrumentMap.put(47, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Timpani
|
||||
|
||||
// Ensenble
|
||||
instrumentMap.put(48, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // String Ensemble 1
|
||||
instrumentMap.put(49, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // String Ensemble 2
|
||||
instrumentMap.put(50, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Synth Strings 1
|
||||
instrumentMap.put(51, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Synth Strings 2
|
||||
instrumentMap.put(52, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Choir Aahs
|
||||
instrumentMap.put(53, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Voice Oohs
|
||||
instrumentMap.put(54, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Synth Choir
|
||||
instrumentMap.put(55, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL }); // Orchestra Hit
|
||||
|
||||
// Brass
|
||||
instrumentMap.put(56, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
instrumentMap.put(57, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
instrumentMap.put(58, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
instrumentMap.put(59, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
instrumentMap.put(60, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
instrumentMap.put(61, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
instrumentMap.put(62, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
instrumentMap.put(63, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
|
||||
// Reed
|
||||
instrumentMap.put(64, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(65, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(66, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(67, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(68, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(69, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(70, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(71, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
|
||||
// Pipe
|
||||
instrumentMap.put(72, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(73, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(74, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(75, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(76, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(77, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(78, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
instrumentMap.put(79, new Instrument[] { Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL });
|
||||
|
||||
// Synth Lead
|
||||
instrumentMap.put(80, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(81, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(82, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(83, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(84, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(85, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(86, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(87, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
|
||||
// Synth Pad
|
||||
instrumentMap.put(88, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(89, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(90, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(91, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(92, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(93, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(94, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(95, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
|
||||
// Synth Effects
|
||||
// instrumentMap.put(96, new Instrument[]{});
|
||||
// instrumentMap.put(97, new Instrument[]{});
|
||||
instrumentMap.put(98, new Instrument[] { Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
instrumentMap.put(99, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(100, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(101, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(102, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(103, new Instrument[] { Instrument.HARP, Instrument.BASS, Instrument.BELL });
|
||||
|
||||
// Ethnic
|
||||
instrumentMap.put(104, new Instrument[] { Instrument.BANJO, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(105, new Instrument[] { Instrument.BANJO, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(106, new Instrument[] { Instrument.BANJO, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(107, new Instrument[] { Instrument.BANJO, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(108, new Instrument[] { Instrument.BANJO, Instrument.BASS, Instrument.BELL });
|
||||
instrumentMap.put(109, new Instrument[] { Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
instrumentMap.put(110, new Instrument[] { Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
instrumentMap.put(111, new Instrument[] { Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL });
|
||||
|
||||
// Percussive
|
||||
instrumentMap.put(112, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
|
||||
instrumentMap.put(113, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
|
||||
instrumentMap.put(114, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
|
||||
instrumentMap.put(115, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
|
||||
instrumentMap.put(116, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
|
||||
instrumentMap.put(117, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
|
||||
instrumentMap.put(118, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
|
||||
instrumentMap.put(119, new Instrument[] { Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE });
|
||||
}
|
||||
|
||||
static {
|
||||
percussionMap.put(35, 10 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(36, 6 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(37, 6 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(38, 8 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(39, 6 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(40, 4 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(41, 6 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(42, 22 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(43, 13 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(44, 22 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(45, 15 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(46, 18 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(47, 20 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(48, 23 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(49, 17 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(50, 23 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(51, 24 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(52, 8 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(53, 13 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(54, 18 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(55, 18 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(56, 1 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(57, 13 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(58, 2 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(59, 13 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(60, 9 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(61, 2 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(62, 8 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(63, 22 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(64, 15 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(65, 13 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(66, 8 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(67, 8 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(68, 3 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(69, 20 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(70, 23 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(71, 24 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(72, 24 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(73, 17 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(74, 11 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(75, 18 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(76, 9 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(77, 5 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(78, 22 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(79, 19 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(80, 17 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(81, 22 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(82, 22 + 25 * Instrument.SNARE.id);
|
||||
percussionMap.put(83, 24 + 25 * Instrument.CHIME.id);
|
||||
percussionMap.put(84, 24 + 25 * Instrument.CHIME.id);
|
||||
percussionMap.put(85, 21 + 25 * Instrument.HAT.id);
|
||||
percussionMap.put(86, 14 + 25 * Instrument.BASEDRUM.id);
|
||||
percussionMap.put(87, 7 + 25 * Instrument.BASEDRUM.id);
|
||||
}
|
||||
|
||||
public static Song getSongFromUrl (final URL url) throws IOException, InvalidMidiDataException, URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
|
||||
final Sequence sequence = MidiSystem.getSequence(DownloadUtilities.DownloadToInputStream(url));
|
||||
return getSong(sequence, Paths.get(url.toURI().getPath()).getFileName().toString());
|
||||
}
|
||||
|
||||
public static Song getSongFromFile (final File file) throws InvalidMidiDataException, IOException {
|
||||
final Sequence sequence = MidiSystem.getSequence(file);
|
||||
return getSong(sequence, file.getName());
|
||||
}
|
||||
|
||||
public static Song getSongFromBytes (final byte[] bytes, final String name) throws InvalidMidiDataException, IOException {
|
||||
final Sequence sequence = MidiSystem.getSequence(new ByteArrayInputStream(bytes));
|
||||
return getSong(sequence, name);
|
||||
}
|
||||
|
||||
public static Song getSong (final Sequence sequence, final String name) {
|
||||
final Song song = new Song(name);
|
||||
|
||||
final long tpq = sequence.getResolution();
|
||||
|
||||
final ArrayList<MidiEvent> tempoEvents = new ArrayList<>();
|
||||
for (final Track track : sequence.getTracks()) {
|
||||
for (int i = 0; i < track.size(); i++) {
|
||||
final MidiEvent event = track.get(i);
|
||||
final MidiMessage message = event.getMessage();
|
||||
if (message instanceof final MetaMessage mm) {
|
||||
if (mm.getType() == SET_TEMPO) {
|
||||
tempoEvents.add(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(tempoEvents, (a, b) -> Long.compare(a.getTick(), b.getTick()));
|
||||
|
||||
for (Track track : sequence.getTracks()) {
|
||||
|
||||
long microTime = 0;
|
||||
int[] ids = new int[16];
|
||||
int mpq = 500000;
|
||||
int tempoEventIdx = 0;
|
||||
long prevTick = 0;
|
||||
|
||||
for (int i = 0; i < track.size(); i++) {
|
||||
MidiEvent event = track.get(i);
|
||||
MidiMessage message = event.getMessage();
|
||||
|
||||
while (tempoEventIdx < tempoEvents.size() && event.getTick() > tempoEvents.get(tempoEventIdx).getTick()) {
|
||||
long deltaTick = tempoEvents.get(tempoEventIdx).getTick() - prevTick;
|
||||
prevTick = tempoEvents.get(tempoEventIdx).getTick();
|
||||
microTime += (mpq/tpq) * deltaTick;
|
||||
|
||||
MetaMessage mm = (MetaMessage) tempoEvents.get(tempoEventIdx).getMessage();
|
||||
byte[] data = mm.getData();
|
||||
int new_mpq = (data[2]&0xFF) | ((data[1]&0xFF)<<8) | ((data[0]&0xFF)<<16);
|
||||
if (new_mpq != 0) mpq = new_mpq;
|
||||
tempoEventIdx++;
|
||||
Collections.sort(tempoEvents, (a, b) -> Long.compare(a.getTick(), b.getTick()));
|
||||
|
||||
for (final Track track : sequence.getTracks()) {
|
||||
|
||||
long microTime = 0;
|
||||
final int[] ids = new int[16];
|
||||
int mpq = 500000;
|
||||
int tempoEventIdx = 0;
|
||||
long prevTick = 0;
|
||||
|
||||
for (int i = 0; i < track.size(); i++) {
|
||||
final MidiEvent event = track.get(i);
|
||||
final MidiMessage message = event.getMessage();
|
||||
|
||||
while (tempoEventIdx < tempoEvents.size() && event.getTick() > tempoEvents.get(tempoEventIdx).getTick()) {
|
||||
final long deltaTick = tempoEvents.get(tempoEventIdx).getTick() - prevTick;
|
||||
prevTick = tempoEvents.get(tempoEventIdx).getTick();
|
||||
microTime += (mpq / tpq) * deltaTick;
|
||||
|
||||
final MetaMessage mm = (MetaMessage) tempoEvents.get(tempoEventIdx).getMessage();
|
||||
final byte[] data = mm.getData();
|
||||
final int new_mpq = (data[2] & 0xFF) | ((data[1] & 0xFF) << 8) | ((data[0] & 0xFF) << 16);
|
||||
if (new_mpq != 0) mpq = new_mpq;
|
||||
tempoEventIdx++;
|
||||
}
|
||||
|
||||
if (message instanceof final ShortMessage sm) {
|
||||
if (sm.getCommand() == SET_INSTRUMENT) {
|
||||
ids[sm.getChannel()] = sm.getData1();
|
||||
} else if (sm.getCommand() == NOTE_ON) {
|
||||
if (sm.getData2() == 0) continue;
|
||||
final int pitch = sm.getData1();
|
||||
final int velocity = sm.getData2();
|
||||
final long deltaTick = event.getTick() - prevTick;
|
||||
prevTick = event.getTick();
|
||||
microTime += (mpq / tpq) * deltaTick;
|
||||
|
||||
final Note note;
|
||||
if (sm.getChannel() == 9) {
|
||||
note = getMidiPercussionNote(pitch, velocity, microTime);
|
||||
} else {
|
||||
note = getMidiInstrumentNote(ids[sm.getChannel()], pitch, velocity, microTime);
|
||||
}
|
||||
if (note != null) {
|
||||
song.add(note);
|
||||
}
|
||||
|
||||
final long time = microTime / 1000L;
|
||||
if (time > song.length) {
|
||||
song.length = time;
|
||||
}
|
||||
} else if (sm.getCommand() == NOTE_OFF) {
|
||||
final long deltaTick = event.getTick() - prevTick;
|
||||
prevTick = event.getTick();
|
||||
microTime += (mpq / tpq) * deltaTick;
|
||||
final long time = microTime / 1000L;
|
||||
if (time > song.length) {
|
||||
song.length = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message instanceof ShortMessage) {
|
||||
ShortMessage sm = (ShortMessage) message;
|
||||
if (sm.getCommand() == SET_INSTRUMENT) {
|
||||
ids[sm.getChannel()] = sm.getData1();
|
||||
}
|
||||
else if (sm.getCommand() == NOTE_ON) {
|
||||
if (sm.getData2() == 0) continue;
|
||||
int pitch = sm.getData1();
|
||||
int velocity = sm.getData2();
|
||||
long deltaTick = event.getTick() - prevTick;
|
||||
prevTick = event.getTick();
|
||||
microTime += (mpq/tpq) * deltaTick;
|
||||
|
||||
Note note;
|
||||
if (sm.getChannel() == 9) {
|
||||
note = getMidiPercussionNote(pitch, velocity, microTime);
|
||||
}
|
||||
else {
|
||||
note = getMidiInstrumentNote(ids[sm.getChannel()], pitch, velocity, microTime);
|
||||
}
|
||||
if (note != null) {
|
||||
song.add(note);
|
||||
}
|
||||
song.sort();
|
||||
|
||||
long time = microTime / 1000L;
|
||||
if (time > song.length) {
|
||||
song.length = time;
|
||||
return song;
|
||||
}
|
||||
|
||||
public static Note getMidiInstrumentNote (final int midiInstrument, final int midiPitch, final int velocity, final long microTime) {
|
||||
Instrument instrument = null;
|
||||
final Instrument[] instrumentList = instrumentMap.get(midiInstrument);
|
||||
if (instrumentList != null) {
|
||||
for (final Instrument candidateInstrument : instrumentList) {
|
||||
if (midiPitch >= candidateInstrument.offset && midiPitch <= candidateInstrument.offset + 24) {
|
||||
instrument = candidateInstrument;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sm.getCommand() == NOTE_OFF) {
|
||||
long deltaTick = event.getTick() - prevTick;
|
||||
prevTick = event.getTick();
|
||||
microTime += (mpq/tpq) * deltaTick;
|
||||
long time = microTime / 1000L;
|
||||
if (time > song.length) {
|
||||
song.length = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
song.sort();
|
||||
|
||||
return song;
|
||||
}
|
||||
|
||||
public static Note getMidiInstrumentNote(int midiInstrument, int midiPitch, int velocity, long microTime) {
|
||||
Instrument instrument = null;
|
||||
Instrument[] instrumentList = instrumentMap.get(midiInstrument);
|
||||
if (instrumentList != null) {
|
||||
for (Instrument candidateInstrument : instrumentList) {
|
||||
if (midiPitch >= candidateInstrument.offset && midiPitch <= candidateInstrument.offset+24) {
|
||||
instrument = candidateInstrument;
|
||||
break;
|
||||
if (instrument == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final int pitch = midiPitch - instrument.offset;
|
||||
final float volume = (float) velocity / 127.0f;
|
||||
final long time = microTime / 1000L;
|
||||
|
||||
return new Note(instrument, pitch, volume, time, Vec3d.ZERO);
|
||||
}
|
||||
|
||||
if (instrument == null) {
|
||||
return null;
|
||||
private static Note getMidiPercussionNote (final int midiPitch, final int velocity, final long microTime) {
|
||||
if (percussionMap.containsKey(midiPitch)) {
|
||||
final int noteId = percussionMap.get(midiPitch);
|
||||
final int pitch = noteId % 25;
|
||||
final float volume = (float) velocity / 127.0f;
|
||||
final Instrument instrument = Instrument.fromId(noteId / 25);
|
||||
final long time = microTime / 1000L;
|
||||
|
||||
return new Note(instrument, pitch, volume, time, Vec3d.ZERO);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int pitch = midiPitch-instrument.offset;
|
||||
float volume = (float) velocity / 127.0f;
|
||||
long time = microTime / 1000L;
|
||||
|
||||
return new Note(instrument, pitch, volume, time);
|
||||
}
|
||||
|
||||
private static Note getMidiPercussionNote (int midiPitch, int velocity, long microTime) {
|
||||
if (percussionMap.containsKey(midiPitch)) {
|
||||
int noteId = percussionMap.get(midiPitch);
|
||||
int pitch = noteId % 25;
|
||||
float volume = (float) velocity / 127.0f;
|
||||
Instrument instrument = Instrument.fromId(noteId / 25);
|
||||
long time = microTime / 1000L;
|
||||
|
||||
return new Note(instrument, pitch, volume, time);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static HashMap<Integer, Instrument[]> instrumentMap = new HashMap<>();
|
||||
static {
|
||||
// Piano (HARP BASS BELL)
|
||||
instrumentMap.put(0, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Acoustic Grand Piano
|
||||
instrumentMap.put(1, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Bright Acoustic Piano
|
||||
instrumentMap.put(2, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Electric Grand Piano
|
||||
instrumentMap.put(3, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Honky-tonk Piano
|
||||
instrumentMap.put(4, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Electric Piano 1
|
||||
instrumentMap.put(5, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Electric Piano 2
|
||||
instrumentMap.put(6, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Harpsichord
|
||||
instrumentMap.put(7, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Clavinet
|
||||
|
||||
// Chromatic Percussion (IRON_XYLOPHONE XYLOPHONE BASS)
|
||||
instrumentMap.put(8, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Celesta
|
||||
instrumentMap.put(9, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Glockenspiel
|
||||
instrumentMap.put(10, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Music Box
|
||||
instrumentMap.put(11, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Vibraphone
|
||||
instrumentMap.put(12, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Marimba
|
||||
instrumentMap.put(13, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Xylophone
|
||||
instrumentMap.put(14, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Tubular Bells
|
||||
instrumentMap.put(15, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE}); // Dulcimer
|
||||
|
||||
// Organ (BIT DIDGERIDOO BELL)
|
||||
instrumentMap.put(16, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Drawbar Organ
|
||||
instrumentMap.put(17, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Percussive Organ
|
||||
instrumentMap.put(18, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Rock Organ
|
||||
instrumentMap.put(19, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Church Organ
|
||||
instrumentMap.put(20, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Reed Organ
|
||||
instrumentMap.put(21, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Accordian
|
||||
instrumentMap.put(22, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Harmonica
|
||||
instrumentMap.put(23, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Tango Accordian
|
||||
|
||||
// Guitar (BIT DIDGERIDOO BELL)
|
||||
instrumentMap.put(24, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Acoustic Guitar (nylon)
|
||||
instrumentMap.put(25, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Acoustic Guitar (steel)
|
||||
instrumentMap.put(26, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Electric Guitar (jazz)
|
||||
instrumentMap.put(27, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Electric Guitar (clean)
|
||||
instrumentMap.put(28, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Electric Guitar (muted)
|
||||
instrumentMap.put(29, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Overdriven Guitar
|
||||
instrumentMap.put(30, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Distortion Guitar
|
||||
instrumentMap.put(31, new Instrument[]{Instrument.GUITAR, Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Guitar Harmonics
|
||||
|
||||
// Bass
|
||||
instrumentMap.put(32, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Acoustic Bass
|
||||
instrumentMap.put(33, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Electric Bass (finger)
|
||||
instrumentMap.put(34, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Electric Bass (pick)
|
||||
instrumentMap.put(35, new Instrument[]{Instrument.BASS, Instrument.HARP, Instrument.BELL}); // Fretless Bass
|
||||
instrumentMap.put(36, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Slap Bass 1
|
||||
instrumentMap.put(37, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Slap Bass 2
|
||||
instrumentMap.put(38, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Synth Bass 1
|
||||
instrumentMap.put(39, new Instrument[]{Instrument.DIDGERIDOO, Instrument.BIT, Instrument.XYLOPHONE}); // Synth Bass 2
|
||||
|
||||
// Strings
|
||||
instrumentMap.put(40, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Violin
|
||||
instrumentMap.put(41, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Viola
|
||||
instrumentMap.put(42, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Cello
|
||||
instrumentMap.put(43, new Instrument[]{Instrument.FLUTE, Instrument.GUITAR, Instrument.BASS, Instrument.BELL}); // Contrabass
|
||||
instrumentMap.put(44, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL}); // Tremolo Strings
|
||||
instrumentMap.put(45, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Pizzicato Strings
|
||||
instrumentMap.put(46, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.CHIME}); // Orchestral Harp
|
||||
instrumentMap.put(47, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Timpani
|
||||
|
||||
// Ensenble
|
||||
instrumentMap.put(48, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // String Ensemble 1
|
||||
instrumentMap.put(49, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // String Ensemble 2
|
||||
instrumentMap.put(50, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Synth Strings 1
|
||||
instrumentMap.put(51, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Synth Strings 2
|
||||
instrumentMap.put(52, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Choir Aahs
|
||||
instrumentMap.put(53, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Voice Oohs
|
||||
instrumentMap.put(54, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Synth Choir
|
||||
instrumentMap.put(55, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL}); // Orchestra Hit
|
||||
|
||||
// Brass
|
||||
instrumentMap.put(56, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(57, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(58, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(59, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(60, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(61, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(62, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(63, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
|
||||
// Reed
|
||||
instrumentMap.put(64, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(65, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(66, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(67, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(68, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(69, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(70, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(71, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
|
||||
// Pipe
|
||||
instrumentMap.put(72, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(73, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(74, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(75, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(76, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(77, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(78, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
instrumentMap.put(79, new Instrument[]{Instrument.FLUTE, Instrument.DIDGERIDOO, Instrument.IRON_XYLOPHONE, Instrument.BELL});
|
||||
|
||||
// Synth Lead
|
||||
instrumentMap.put(80, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(81, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(82, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(83, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(84, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(85, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(86, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(87, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
|
||||
// Synth Pad
|
||||
instrumentMap.put(88, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(89, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(90, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(91, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(92, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(93, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(94, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(95, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
|
||||
// Synth Effects
|
||||
// instrumentMap.put(96, new Instrument[]{});
|
||||
// instrumentMap.put(97, new Instrument[]{});
|
||||
instrumentMap.put(98, new Instrument[]{Instrument.BIT, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(99, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(100, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(101, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(102, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(103, new Instrument[]{Instrument.HARP, Instrument.BASS, Instrument.BELL});
|
||||
|
||||
// Ethnic
|
||||
instrumentMap.put(104, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(105, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(106, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(107, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(108, new Instrument[]{Instrument.BANJO, Instrument.BASS, Instrument.BELL});
|
||||
instrumentMap.put(109, new Instrument[]{Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(110, new Instrument[]{Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
instrumentMap.put(111, new Instrument[]{Instrument.HARP, Instrument.DIDGERIDOO, Instrument.BELL});
|
||||
|
||||
// Percussive
|
||||
instrumentMap.put(112, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(113, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(114, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(115, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(116, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(117, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(118, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
instrumentMap.put(119, new Instrument[]{Instrument.IRON_XYLOPHONE, Instrument.BASS, Instrument.XYLOPHONE});
|
||||
}
|
||||
|
||||
public static HashMap<Integer, Integer> percussionMap = new HashMap<>();
|
||||
static {
|
||||
percussionMap.put(35, 10 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(36, 6 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(37, 6 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(38, 8 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(39, 6 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(40, 4 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(41, 6 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(42, 22 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(43, 13 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(44, 22 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(45, 15 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(46, 18 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(47, 20 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(48, 23 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(49, 17 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(50, 23 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(51, 24 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(52, 8 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(53, 13 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(54, 18 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(55, 18 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(56, 1 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(57, 13 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(58, 2 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(59, 13 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(60, 9 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(61, 2 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(62, 8 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(63, 22 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(64, 15 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(65, 13 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(66, 8 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(67, 8 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(68, 3 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(69, 20 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(70, 23 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(71, 24 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(72, 24 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(73, 17 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(74, 11 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(75, 18 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(76, 9 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(77, 5 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(78, 22 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(79, 19 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(80, 17 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(81, 22 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(82, 22 + 25*Instrument.SNARE.id);
|
||||
percussionMap.put(83, 24 + 25*Instrument.CHIME.id);
|
||||
percussionMap.put(84, 24 + 25*Instrument.CHIME.id);
|
||||
percussionMap.put(85, 21 + 25*Instrument.HAT.id);
|
||||
percussionMap.put(86, 14 + 25*Instrument.BASEDRUM.id);
|
||||
percussionMap.put(87, 7 + 25*Instrument.BASEDRUM.id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,197 +1,225 @@
|
|||
package land.chipmunk.chipmunkmod.song;
|
||||
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class NBSConverter {
|
||||
public static Instrument[] instrumentIndex = new Instrument[] {
|
||||
Instrument.HARP,
|
||||
Instrument.BASS,
|
||||
Instrument.BASEDRUM,
|
||||
Instrument.SNARE,
|
||||
Instrument.HAT,
|
||||
Instrument.GUITAR,
|
||||
Instrument.FLUTE,
|
||||
Instrument.BELL,
|
||||
Instrument.CHIME,
|
||||
Instrument.XYLOPHONE,
|
||||
Instrument.IRON_XYLOPHONE,
|
||||
Instrument.COW_BELL,
|
||||
Instrument.DIDGERIDOO,
|
||||
Instrument.BIT,
|
||||
Instrument.BANJO,
|
||||
Instrument.PLING,
|
||||
};
|
||||
public static Instrument[] instrumentIndex = new Instrument[] {
|
||||
Instrument.HARP,
|
||||
Instrument.BASS,
|
||||
Instrument.BASEDRUM,
|
||||
Instrument.SNARE,
|
||||
Instrument.HAT,
|
||||
Instrument.GUITAR,
|
||||
Instrument.FLUTE,
|
||||
Instrument.BELL,
|
||||
Instrument.CHIME,
|
||||
Instrument.XYLOPHONE,
|
||||
Instrument.IRON_XYLOPHONE,
|
||||
Instrument.COW_BELL,
|
||||
Instrument.DIDGERIDOO,
|
||||
Instrument.BIT,
|
||||
Instrument.BANJO,
|
||||
Instrument.PLING,
|
||||
};
|
||||
|
||||
private static class NBSNote {
|
||||
public int tick;
|
||||
public short layer;
|
||||
public byte instrument;
|
||||
public byte key;
|
||||
public byte velocity = 100;
|
||||
public byte panning = 100;
|
||||
public short pitch = 0;
|
||||
}
|
||||
public static Song getSongFromBytes (final byte[] bytes, final String fileName) throws IOException {
|
||||
final ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
private static class NBSLayer {
|
||||
public String name;
|
||||
public byte lock = 0;
|
||||
public byte volume;
|
||||
public byte stereo = 100;
|
||||
}
|
||||
short songLength = 0;
|
||||
byte format = 0;
|
||||
byte vanillaInstrumentCount = 0;
|
||||
songLength = buffer.getShort(); // If it's not 0, then it uses the old format
|
||||
if (songLength == 0) {
|
||||
format = buffer.get();
|
||||
}
|
||||
|
||||
private static class NBSCustomInstrument {
|
||||
public String name;
|
||||
public String file;
|
||||
public byte pitch = 0;
|
||||
public boolean key = false;
|
||||
}
|
||||
if (format >= 1) {
|
||||
vanillaInstrumentCount = buffer.get();
|
||||
}
|
||||
if (format >= 3) {
|
||||
songLength = buffer.getShort();
|
||||
}
|
||||
|
||||
public static Song getSongFromBytes(byte[] bytes, String fileName) throws IOException {
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
final short layerCount = buffer.getShort();
|
||||
final String songName = getString(buffer, bytes.length);
|
||||
final String songAuthor = getString(buffer, bytes.length);
|
||||
final String songOriginalAuthor = getString(buffer, bytes.length);
|
||||
final String songDescription = getString(buffer, bytes.length);
|
||||
final short tempo = buffer.getShort();
|
||||
final byte autoSaving = buffer.get();
|
||||
final byte autoSavingDuration = buffer.get();
|
||||
final byte timeSignature = buffer.get();
|
||||
final int minutesSpent = buffer.getInt();
|
||||
final int leftClicks = buffer.getInt();
|
||||
final int rightClicks = buffer.getInt();
|
||||
final int blocksAdded = buffer.getInt();
|
||||
final int blocksRemoved = buffer.getInt();
|
||||
final String origFileName = getString(buffer, bytes.length);
|
||||
|
||||
short songLength = 0;
|
||||
byte format = 0;
|
||||
byte vanillaInstrumentCount = 0;
|
||||
songLength = buffer.getShort(); // If it's not 0, then it uses the old format
|
||||
if (songLength == 0) {
|
||||
format = buffer.get();
|
||||
}
|
||||
|
||||
if (format >= 1) {
|
||||
vanillaInstrumentCount = buffer.get();
|
||||
}
|
||||
if (format >= 3) {
|
||||
songLength = buffer.getShort();
|
||||
}
|
||||
|
||||
short layerCount = buffer.getShort();
|
||||
String songName = getString(buffer, bytes.length);
|
||||
String songAuthor = getString(buffer, bytes.length);
|
||||
String songOriginalAuthor = getString(buffer, bytes.length);
|
||||
String songDescription = getString(buffer, bytes.length);
|
||||
short tempo = buffer.getShort();
|
||||
byte autoSaving = buffer.get();
|
||||
byte autoSavingDuration = buffer.get();
|
||||
byte timeSignature = buffer.get();
|
||||
int minutesSpent = buffer.getInt();
|
||||
int leftClicks = buffer.getInt();
|
||||
int rightClicks = buffer.getInt();
|
||||
int blocksAdded = buffer.getInt();
|
||||
int blocksRemoved = buffer.getInt();
|
||||
String origFileName = getString(buffer, bytes.length);
|
||||
|
||||
byte loop = 0;
|
||||
byte maxLoopCount = 0;
|
||||
short loopStartTick = 0;
|
||||
if (format >= 4) {
|
||||
loop = buffer.get();
|
||||
maxLoopCount = buffer.get();
|
||||
loopStartTick = buffer.getShort();
|
||||
}
|
||||
|
||||
ArrayList<NBSNote> nbsNotes = new ArrayList<>();
|
||||
short tick = -1;
|
||||
while (true) {
|
||||
int tickJumps = buffer.getShort();
|
||||
if (tickJumps == 0) break;
|
||||
tick += tickJumps;
|
||||
|
||||
short layer = -1;
|
||||
while (true) {
|
||||
int layerJumps = buffer.getShort();
|
||||
if (layerJumps == 0) break;
|
||||
layer += layerJumps;
|
||||
NBSNote note = new NBSNote();
|
||||
note.tick = tick;
|
||||
note.layer = layer;
|
||||
note.instrument = buffer.get();
|
||||
note.key = buffer.get();
|
||||
byte loop = 0;
|
||||
byte maxLoopCount = 0;
|
||||
short loopStartTick = 0;
|
||||
if (format >= 4) {
|
||||
note.velocity = buffer.get();
|
||||
note.panning = buffer.get();
|
||||
note.pitch = buffer.getShort();
|
||||
loop = buffer.get();
|
||||
maxLoopCount = buffer.get();
|
||||
loopStartTick = buffer.getShort();
|
||||
}
|
||||
nbsNotes.add(note);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<NBSLayer> nbsLayers = new ArrayList<>();
|
||||
if (buffer.hasRemaining()) {
|
||||
for (int i=0; i<layerCount; i++) {
|
||||
NBSLayer layer = new NBSLayer();
|
||||
layer.name = getString(buffer, bytes.length);
|
||||
if (format >= 4) {
|
||||
layer.lock = buffer.get();
|
||||
final ArrayList<NBSNote> nbsNotes = new ArrayList<>();
|
||||
short tick = -1;
|
||||
while (true) {
|
||||
final int tickJumps = buffer.getShort();
|
||||
if (tickJumps == 0) break;
|
||||
tick += tickJumps;
|
||||
|
||||
short layer = -1;
|
||||
while (true) {
|
||||
final int layerJumps = buffer.getShort();
|
||||
if (layerJumps == 0) break;
|
||||
layer += layerJumps;
|
||||
final NBSNote note = new NBSNote();
|
||||
note.tick = tick;
|
||||
note.layer = layer;
|
||||
note.instrument = buffer.get();
|
||||
note.key = buffer.get();
|
||||
if (format >= 4) {
|
||||
note.velocity = buffer.get();
|
||||
note.panning = buffer.get();
|
||||
note.pitch = buffer.getShort();
|
||||
}
|
||||
nbsNotes.add(note);
|
||||
}
|
||||
}
|
||||
layer.volume = buffer.get();
|
||||
if (format >= 2) {
|
||||
layer.stereo = buffer.get();
|
||||
|
||||
final ArrayList<NBSLayer> nbsLayers = new ArrayList<>();
|
||||
if (buffer.hasRemaining()) {
|
||||
for (int i = 0; i < layerCount; i++) {
|
||||
final NBSLayer layer = new NBSLayer();
|
||||
layer.name = getString(buffer, bytes.length);
|
||||
if (format >= 4) {
|
||||
layer.lock = buffer.get();
|
||||
}
|
||||
layer.volume = buffer.get();
|
||||
if (format >= 2) {
|
||||
layer.stereo = buffer.get();
|
||||
}
|
||||
nbsLayers.add(layer);
|
||||
}
|
||||
}
|
||||
nbsLayers.add(layer);
|
||||
}
|
||||
|
||||
final ArrayList<NBSCustomInstrument> customInstruments = new ArrayList<>();
|
||||
if (buffer.hasRemaining()) {
|
||||
final byte customInstrumentCount = buffer.get();
|
||||
for (int i = 0; i < customInstrumentCount; i++) {
|
||||
final NBSCustomInstrument customInstrument = new NBSCustomInstrument();
|
||||
customInstrument.name = getString(buffer, bytes.length);
|
||||
customInstrument.file = getString(buffer, bytes.length);
|
||||
customInstrument.pitch = buffer.get();
|
||||
customInstrument.key = buffer.get() != 0;
|
||||
customInstruments.add(customInstrument);
|
||||
}
|
||||
}
|
||||
|
||||
final Song song = new Song(songName.trim().length() > 0 ? songName : fileName);
|
||||
if (loop > 0) {
|
||||
song.looping = true;
|
||||
song.loopPosition = getMilliTime(loopStartTick, tempo);
|
||||
song.loopCount = maxLoopCount;
|
||||
}
|
||||
for (final NBSNote note : nbsNotes) {
|
||||
final Instrument instrument;
|
||||
double key;
|
||||
if (note.instrument < instrumentIndex.length) {
|
||||
instrument = instrumentIndex[note.instrument];
|
||||
|
||||
key = (double) ((note.key * 100) + note.pitch) / 100;
|
||||
} else {
|
||||
final int index = note.instrument - instrumentIndex.length;
|
||||
|
||||
if (index >= customInstruments.size()) continue;
|
||||
|
||||
final NBSCustomInstrument customInstrument = customInstruments.get(index);
|
||||
instrument = Instrument.of(customInstrument.name);
|
||||
|
||||
key = (note.key) + (customInstrument.pitch + (double) note.pitch / 100);
|
||||
}
|
||||
|
||||
byte layerVolume = 100;
|
||||
if (nbsLayers.size() > note.layer) {
|
||||
layerVolume = nbsLayers.get(note.layer).volume;
|
||||
}
|
||||
|
||||
while (key < 33) key += 12;
|
||||
while (key > 57) key -= 12;
|
||||
|
||||
final double pitch = key - 33;
|
||||
|
||||
final int layerStereo = Byte.toUnsignedInt(nbsLayers.get(note.layer).stereo);
|
||||
final int notePanning = Byte.toUnsignedInt(note.panning);
|
||||
|
||||
final double value;
|
||||
|
||||
if (layerStereo == 100 && notePanning != 100) value = notePanning;
|
||||
else if (notePanning == 100 && layerStereo != 100) value = layerStereo;
|
||||
else value = (double) (layerStereo + notePanning) / 2;
|
||||
|
||||
final double x;
|
||||
|
||||
if (value > 100) x = (value - 100) / -100;
|
||||
else if (value == 100) x = 0;
|
||||
else x = ((value - 100) * -1) / 100;
|
||||
|
||||
final Vec3d position = new Vec3d(x, 0, 0);
|
||||
|
||||
song.add(new Note(instrument, pitch, (float) note.velocity * (float) layerVolume / 10000f, getMilliTime(note.tick, tempo), position));
|
||||
}
|
||||
|
||||
song.length = song.get(song.size() - 1).time + 50;
|
||||
|
||||
return song;
|
||||
}
|
||||
|
||||
ArrayList<NBSCustomInstrument> customInstruments = new ArrayList<>();
|
||||
if (buffer.hasRemaining()) {
|
||||
byte customInstrumentCount = buffer.get();
|
||||
for (int i = 0; i < customInstrumentCount; i++) {
|
||||
NBSCustomInstrument customInstrument = new NBSCustomInstrument();
|
||||
customInstrument.name = getString(buffer, bytes.length);
|
||||
customInstrument.file = getString(buffer, bytes.length);
|
||||
customInstrument.pitch = buffer.get();
|
||||
customInstrument.key = buffer.get() == 0 ? false : true;
|
||||
customInstruments.add(customInstrument);
|
||||
}
|
||||
private static String getString (final ByteBuffer buffer, final int maxSize) throws IOException {
|
||||
final int length = buffer.getInt();
|
||||
if (length > maxSize) {
|
||||
throw new IOException("String is too large");
|
||||
}
|
||||
final byte[] arr = new byte[length];
|
||||
buffer.get(arr, 0, length);
|
||||
return new String(arr);
|
||||
}
|
||||
|
||||
Song song = new Song(songName.trim().length() > 0 ? songName : fileName);
|
||||
if (loop > 0) {
|
||||
song.looping = true;
|
||||
song.loopPosition = getMilliTime(loopStartTick, tempo);
|
||||
song.loopCount = maxLoopCount;
|
||||
}
|
||||
for (NBSNote note : nbsNotes) {
|
||||
Instrument instrument;
|
||||
int key = note.key;
|
||||
if (note.instrument < instrumentIndex.length) {
|
||||
instrument = instrumentIndex[note.instrument];
|
||||
} else {
|
||||
int index = note.instrument - instrumentIndex.length;
|
||||
if (index >= customInstruments.size()) continue;
|
||||
NBSCustomInstrument customInstrument = customInstruments.get(index);
|
||||
instrument = Instrument.of(customInstrument.name);
|
||||
key += customInstrument.pitch;
|
||||
}
|
||||
|
||||
byte layerVolume = 100;
|
||||
if (nbsLayers.size() > note.layer) {
|
||||
layerVolume = nbsLayers.get(note.layer).volume;
|
||||
}
|
||||
|
||||
int pitch = key-33;
|
||||
song.add(new Note(instrument, pitch, (float) note.velocity * (float) layerVolume / 10000f, getMilliTime(note.tick, tempo)));
|
||||
private static int getMilliTime (final int tick, final int tempo) {
|
||||
return 1000 * tick * 100 / tempo;
|
||||
}
|
||||
|
||||
song.length = song.get(song.size()-1).time + 50;
|
||||
|
||||
return song;
|
||||
}
|
||||
|
||||
private static String getString (ByteBuffer buffer, int maxSize) throws IOException {
|
||||
int length = buffer.getInt();
|
||||
if (length > maxSize) {
|
||||
throw new IOException("String is too large");
|
||||
private static class NBSNote {
|
||||
public int tick;
|
||||
public short layer;
|
||||
public byte instrument;
|
||||
public byte key;
|
||||
public byte velocity = 100;
|
||||
public byte panning = 100;
|
||||
public short pitch = 0;
|
||||
}
|
||||
byte arr[] = new byte[length];
|
||||
buffer.get(arr, 0, length);
|
||||
return new String(arr);
|
||||
}
|
||||
|
||||
private static int getMilliTime(int tick, int tempo) {
|
||||
return 1000 * tick * 100 / tempo;
|
||||
}
|
||||
private static class NBSLayer {
|
||||
public String name;
|
||||
public byte lock = 0;
|
||||
public byte volume;
|
||||
public byte stereo = 100;
|
||||
}
|
||||
|
||||
private static class NBSCustomInstrument {
|
||||
public String name;
|
||||
public String file;
|
||||
public byte pitch = 0;
|
||||
public boolean key = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +1,25 @@
|
|||
package land.chipmunk.chipmunkmod.song;
|
||||
|
||||
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class Note implements Comparable<Note> {
|
||||
public Instrument instrument;
|
||||
public int pitch;
|
||||
public float volume;
|
||||
public long time;
|
||||
public Instrument instrument;
|
||||
public double pitch;
|
||||
public float volume;
|
||||
public long time;
|
||||
public Vec3d position;
|
||||
|
||||
public Note (Instrument instrument, int pitch, float volume, long time) {
|
||||
this.instrument = instrument;
|
||||
this.pitch = pitch;
|
||||
this.volume = volume;
|
||||
this.time = time;
|
||||
}
|
||||
public Note (final Instrument instrument, final double pitch, final float volume, final long time, final Vec3d position) {
|
||||
this.instrument = instrument;
|
||||
this.pitch = pitch;
|
||||
this.volume = volume;
|
||||
this.time = time;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Note other) {
|
||||
if (time < other.time) {
|
||||
return -1;
|
||||
@Override
|
||||
public int compareTo (final Note other) {
|
||||
return Long.compare(time, other.time);
|
||||
}
|
||||
else if (time > other.time) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int noteId () {
|
||||
return pitch + instrument.id * 25;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,131 +1,132 @@
|
|||
package land.chipmunk.chipmunkmod.song;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
public class Song {
|
||||
public ArrayList<Note> notes = new ArrayList<>();
|
||||
public Component name;
|
||||
public int position = 0; // Current note index
|
||||
public boolean looping = false;
|
||||
public boolean paused = true;
|
||||
public long startTime = 0; // Start time in millis since unix epoch
|
||||
public long length = 0; // Milliseconds in the song
|
||||
public long time = 0; // Time since start of song
|
||||
public long loopPosition = 0; // Milliseconds into the song to start looping
|
||||
public int loopCount = 0; // Number of times to loop
|
||||
public int currentLoop = 0; // Number of loops so far
|
||||
|
||||
public Song (Component name) {
|
||||
this.name = name;
|
||||
}
|
||||
public ArrayList<Note> notes = new ArrayList<>();
|
||||
public Component name;
|
||||
public int position = 0; // Current note index
|
||||
public boolean looping = false;
|
||||
public boolean paused = true;
|
||||
public long startTime = 0; // Start time in millis since unix epoch
|
||||
public long length = 0; // Milliseconds in the song
|
||||
public long time = 0; // Time since start of song
|
||||
public long loopPosition = 0; // Milliseconds into the song to start looping
|
||||
public int loopCount = 0; // Number of times to loop
|
||||
public int currentLoop = 0; // Number of loops so far
|
||||
|
||||
public Song (String name) {
|
||||
this(Component.text(name));
|
||||
}
|
||||
|
||||
public Note get (int i) {
|
||||
return notes.get(i);
|
||||
}
|
||||
|
||||
public void add (Note e) {
|
||||
notes.add(e);
|
||||
}
|
||||
|
||||
public void sort () {
|
||||
Collections.sort(notes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts playing song (does nothing if already playing)
|
||||
*/
|
||||
public void play () {
|
||||
if (paused) {
|
||||
paused = false;
|
||||
startTime = System.currentTimeMillis() - time;
|
||||
public Song (final Component name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses song (does nothing if already paused)
|
||||
*/
|
||||
public void pause () {
|
||||
if (!paused) {
|
||||
paused = true;
|
||||
// Recalculates time so that the song will continue playing after the exact point it was paused
|
||||
advanceTime();
|
||||
public Song (final String name) {
|
||||
this(Component.text(name));
|
||||
}
|
||||
}
|
||||
|
||||
public void setTime (long t) {
|
||||
time = t;
|
||||
startTime = System.currentTimeMillis() - time;
|
||||
position = 0;
|
||||
while (position < notes.size() && notes.get(position).time < t) {
|
||||
position++;
|
||||
public Note get (final int i) {
|
||||
return notes.get(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void advanceTime () {
|
||||
time = System.currentTimeMillis() - startTime;
|
||||
}
|
||||
public void add (final Note e) {
|
||||
notes.add(e);
|
||||
}
|
||||
|
||||
public boolean reachedNextNote () {
|
||||
if (position < notes.size()) {
|
||||
return notes.get(position).time <= time;
|
||||
} else {
|
||||
if (time > length && shouldLoop()) {
|
||||
loop();
|
||||
if (position < notes.size()) {
|
||||
return notes.get(position).time <= time;
|
||||
} else {
|
||||
return false;
|
||||
public void sort () {
|
||||
Collections.sort(notes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts playing song (does nothing if already playing)
|
||||
*/
|
||||
public void play () {
|
||||
if (paused) {
|
||||
paused = false;
|
||||
startTime = System.currentTimeMillis() - time;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Note getNextNote () {
|
||||
if (position >= notes.size()) {
|
||||
if (shouldLoop()) {
|
||||
loop();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Pauses song (does nothing if already paused)
|
||||
*/
|
||||
public void pause () {
|
||||
if (!paused) {
|
||||
paused = true;
|
||||
// Recalculates time so that the song will continue playing after the exact point it was paused
|
||||
advanceTime();
|
||||
}
|
||||
}
|
||||
return notes.get(position++);
|
||||
}
|
||||
|
||||
public boolean finished () {
|
||||
return time > length && !shouldLoop();
|
||||
}
|
||||
|
||||
private void loop () {
|
||||
position = 0;
|
||||
startTime += length - loopPosition;
|
||||
time -= length - loopPosition;
|
||||
while (position < notes.size() && notes.get(position).time < loopPosition) {
|
||||
position++;
|
||||
public void setTime (final long t) {
|
||||
time = t;
|
||||
startTime = System.currentTimeMillis() - time;
|
||||
position = 0;
|
||||
while (position < notes.size() && notes.get(position).time < t) {
|
||||
position++;
|
||||
}
|
||||
}
|
||||
currentLoop++;
|
||||
}
|
||||
|
||||
private boolean shouldLoop () {
|
||||
if (looping) {
|
||||
if (loopCount == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return currentLoop < loopCount;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
public void advanceTime () {
|
||||
time = System.currentTimeMillis() - startTime;
|
||||
}
|
||||
}
|
||||
|
||||
public int size () {
|
||||
return notes.size();
|
||||
}
|
||||
public boolean reachedNextNote () {
|
||||
if (position < notes.size()) {
|
||||
return notes.get(position).time <= time;
|
||||
} else {
|
||||
if (time > length && shouldLoop()) {
|
||||
loop();
|
||||
if (position < notes.size()) {
|
||||
return notes.get(position).time <= time;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Note getNextNote () {
|
||||
if (position >= notes.size()) {
|
||||
if (shouldLoop()) {
|
||||
loop();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return notes.get(position++);
|
||||
}
|
||||
|
||||
public boolean finished () {
|
||||
return time > length && !shouldLoop();
|
||||
}
|
||||
|
||||
private void loop () {
|
||||
position = 0;
|
||||
startTime += length - loopPosition;
|
||||
time -= length - loopPosition;
|
||||
while (position < notes.size() && notes.get(position).time < loopPosition) {
|
||||
position++;
|
||||
}
|
||||
currentLoop++;
|
||||
}
|
||||
|
||||
private boolean shouldLoop () {
|
||||
if (looping) {
|
||||
if (loopCount == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return currentLoop < loopCount;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int size () {
|
||||
return notes.size();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,20 +3,20 @@ package land.chipmunk.chipmunkmod.song;
|
|||
import net.minecraft.text.Text;
|
||||
|
||||
public class SongLoaderException extends Exception {
|
||||
public final Text message;
|
||||
public final Text message;
|
||||
|
||||
public SongLoaderException (Text message) {
|
||||
super();
|
||||
this.message = message;
|
||||
}
|
||||
public SongLoaderException (final Text message) {
|
||||
super();
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public SongLoaderException (Text message, Throwable cause) {
|
||||
super(null, cause);
|
||||
this.message = message;
|
||||
}
|
||||
public SongLoaderException (final Text message, final Throwable cause) {
|
||||
super(null, cause);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage () {
|
||||
return message.getString();
|
||||
}
|
||||
@Override
|
||||
public String getMessage () {
|
||||
return message.getString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,63 +6,63 @@ import net.minecraft.text.Text;
|
|||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class SongLoaderThread extends Thread {
|
||||
private String location;
|
||||
private File songPath;
|
||||
private URL songUrl;
|
||||
public SongLoaderException exception;
|
||||
public Song song;
|
||||
public SongLoaderException exception;
|
||||
public Song song;
|
||||
private String location;
|
||||
private File songPath;
|
||||
private URL songUrl;
|
||||
private final boolean isUrl;
|
||||
|
||||
private boolean isUrl;
|
||||
|
||||
public SongLoaderThread (URL location) throws SongLoaderException {
|
||||
isUrl = true;
|
||||
songUrl = location;
|
||||
}
|
||||
|
||||
public SongLoaderThread (Path location) throws SongLoaderException {
|
||||
isUrl = false;
|
||||
songPath = location.toFile();
|
||||
}
|
||||
|
||||
public void run () {
|
||||
byte[] bytes;
|
||||
String name;
|
||||
try {
|
||||
if (isUrl) {
|
||||
bytes = DownloadUtilities.DownloadToByteArray(songUrl);
|
||||
name = Paths.get(songUrl.toURI().getPath()).getFileName().toString();
|
||||
} else {
|
||||
bytes = Files.readAllBytes(songPath.toPath());
|
||||
name = songPath.getName();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
exception = new SongLoaderException(Text.literal(e.getMessage()), e);
|
||||
return;
|
||||
public SongLoaderThread (final URL location) throws SongLoaderException {
|
||||
isUrl = true;
|
||||
songUrl = location;
|
||||
}
|
||||
|
||||
try {
|
||||
song = MidiConverter.getSongFromBytes(bytes, name);
|
||||
} catch (Exception e) {
|
||||
public SongLoaderThread (final Path location) throws SongLoaderException {
|
||||
isUrl = false;
|
||||
songPath = location.toFile();
|
||||
}
|
||||
|
||||
if (song == null) {
|
||||
try {
|
||||
song = NBSConverter.getSongFromBytes(bytes, name);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
public void run () {
|
||||
final byte[] bytes;
|
||||
final String name;
|
||||
try {
|
||||
if (isUrl) {
|
||||
bytes = DownloadUtilities.DownloadToByteArray(songUrl);
|
||||
name = Paths.get(songUrl.toURI().getPath()).getFileName().toString();
|
||||
} else {
|
||||
bytes = Files.readAllBytes(songPath.toPath());
|
||||
name = songPath.getName();
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
exception = new SongLoaderException(Text.literal(e.getMessage()), e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
song = MidiConverter.getSongFromBytes(bytes, name);
|
||||
} catch (final Exception e) {
|
||||
}
|
||||
|
||||
if (song == null) {
|
||||
try {
|
||||
song = NBSConverter.getSongFromBytes(bytes, name);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (song == null) {
|
||||
exception = new SongLoaderException(Text.translatable("Invalid song format"));
|
||||
}
|
||||
}
|
||||
|
||||
if (song == null) {
|
||||
exception = new SongLoaderException(Text.translatable("Invalid song format"));
|
||||
private File getSongFile (final String name) {
|
||||
return new File(SongPlayer.SONG_DIR, name);
|
||||
}
|
||||
}
|
||||
|
||||
private File getSongFile (String name) {
|
||||
return new File(SongPlayer.SONG_DIR, name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ArrayUtil {
|
||||
public static String[] removeFirst(String[] original,int index) {
|
||||
return Arrays.stream(original).toList().subList(index, original.length).toArray(new String[0]);
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.util;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.entity.attribute.EntityAttribute;
|
||||
import net.minecraft.entity.attribute.EntityAttributeInstance;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class AttributeModifier {
|
||||
/*
|
||||
EntityAttributeInstance movementSpeedAttribute = MC.player.getAttributeInstance(EntityAttributes.GENERIC_MOVEMENT_SPEED);
|
||||
EntityAttributeModifier tempModifier = new EntityAttributeModifier(
|
||||
"TestClient@Speed", // Modifier name
|
||||
3, // Modifier value
|
||||
EntityAttributeModifier.Operation.MULTIPLY_TOTAL); // Modifier operation
|
||||
movementSpeedAttribute.addPersistentModifier(tempModifier);
|
||||
*/
|
||||
String name;
|
||||
EntityAttribute attribute;
|
||||
float value;
|
||||
EntityAttributeModifier.Operation operation;
|
||||
EntityAttributeModifier modifier;
|
||||
EntityAttributeInstance instance;
|
||||
public AttributeModifier(EntityAttribute attribute, float value, EntityAttributeModifier.Operation operation) {
|
||||
this.attribute = attribute;
|
||||
this.value = value;
|
||||
this.operation = operation;
|
||||
name = "TestClient@"+(new Throwable().getStackTrace()[1].getClassName())+"."+(new Throwable().getStackTrace()[1].getMethodName());
|
||||
// Chat.send("Created new attribute modifier " + name);
|
||||
instance = MinecraftClient.getInstance().player.getAttributeInstance(new RegistryEntry.Direct<>(attribute));
|
||||
modifier = new EntityAttributeModifier(Identifier.of(name), value, operation);
|
||||
}
|
||||
|
||||
public void add() {
|
||||
instance.addPersistentModifier(modifier);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
instance.removeModifier(modifier);
|
||||
}
|
||||
|
||||
public boolean isOnPlayer() {
|
||||
return instance.hasModifier(modifier.id());
|
||||
}
|
||||
|
||||
public void setValue(float value) {
|
||||
this.value = value;
|
||||
modifier = new EntityAttributeModifier(Identifier.of(name), value, operation);
|
||||
// remove and add multiplier to refresh value
|
||||
if(isOnPlayer()){
|
||||
remove();
|
||||
add();
|
||||
}
|
||||
}
|
||||
|
||||
public float getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -2,41 +2,41 @@ package land.chipmunk.chipmunkmod.util;
|
|||
|
||||
import com.mojang.brigadier.Command;
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
import land.chipmunk.chipmunkmod.Configuration;
|
||||
import land.chipmunk.chipmunkmod.commands.SayCommand;
|
||||
import land.chipmunk.chipmunkmod.config.Configuration;
|
||||
import land.chipmunk.chipmunkmod.modules.Chat;
|
||||
import land.chipmunk.chipmunkmod.modules.CustomChat;
|
||||
import land.chipmunk.chipmunkmod.modules.custom_chat.CustomChat;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class BotValidationUtilities {
|
||||
public static int hbot (String command) throws RuntimeException {
|
||||
public static int hbot (final String command) throws RuntimeException {
|
||||
final Configuration.BotInfo info = ChipmunkMod.CONFIG.bots.hbot;
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
final String prefix = info.prefix;
|
||||
final String key = info.key;
|
||||
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
if (key == null)
|
||||
throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
String time = String.valueOf(System.currentTimeMillis() / 10000);
|
||||
String input = prefix + command.replaceAll("&[0-9a-fklmnor]", "") + ";" + client.player.getName().getString() + ";" + time + ";" + key;
|
||||
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
|
||||
String stringHash = bigInt.toString(Character.MAX_RADIX);
|
||||
final MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
final String time = String.valueOf(System.currentTimeMillis() / 10000);
|
||||
final String input = prefix + command.replaceAll("&[0-9a-fklmnor]", "") + ";" + client.player.getUuidAsString() + ";" + time + ";" + key;
|
||||
final byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
final BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
|
||||
final String stringHash = bigInt.toString(Character.MAX_RADIX);
|
||||
|
||||
Chat.sendChatMessage(prefix + command + " " + stringHash, true);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ public class BotValidationUtilities {
|
|||
String time = String.valueOf(System.currentTimeMillis() / 10000);
|
||||
String input = "babyboom:" + key + ":" + client.player.getUuidAsString() + ":" + command.replaceAll("&[0-9a-fklmnor]", "") + ":" + time;
|
||||
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
String stringHash = Hexadecimal.encode(hash);
|
||||
String stringHash = new String(Hex.encodeHex(hash));
|
||||
|
||||
Chat.sendChatMessage(prefix + command + " " + stringHash, true);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
|
@ -81,7 +81,7 @@ public class BotValidationUtilities {
|
|||
String time = String.valueOf(System.currentTimeMillis() / 10000);
|
||||
String input = "babyboom:" + key + ":" + client.player.getUuidAsString() + ":" + command.replaceAll("&[0-9a-fklmnor]", "") + ":" + time;
|
||||
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
String stringHash = Hexadecimal.encode(hash);
|
||||
String stringHash = new String(Hex.encodeHex(hash));
|
||||
|
||||
Chat.sendChatMessage(prefix + command + " " + stringHash, true);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
|
@ -91,33 +91,34 @@ public class BotValidationUtilities {
|
|||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int sbot (String command) throws RuntimeException {
|
||||
public static int sbot (final String command) throws RuntimeException {
|
||||
final Configuration.BotInfo info = ChipmunkMod.CONFIG.bots.sbot;
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler();
|
||||
|
||||
final String prefix = info.prefix;
|
||||
final String key = info.key;
|
||||
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
if (key == null)
|
||||
throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
String time = String.valueOf(System.currentTimeMillis() / 20000);
|
||||
String input = prefix + command.replaceAll("&[0-9a-fklmnorx]", "") + ";" + client.player.getName().getString() + ";" + time + ";" + key;
|
||||
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
|
||||
String stringHash = bigInt.toString(Character.MAX_RADIX);
|
||||
final MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
final String time = String.valueOf(System.currentTimeMillis() / 20000);
|
||||
final String input = prefix + command.replaceAll("&[0-9a-fklmnorx]", "") + ";" + client.player.getName().getString() + ";" + time + ";" + key;
|
||||
final byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
final BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
|
||||
final String stringHash = bigInt.toString(Character.MAX_RADIX);
|
||||
|
||||
Chat.sendChatMessage(prefix + command + " " + stringHash, true);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int chomens (String command) throws RuntimeException {
|
||||
final Configuration.ChomeNSBotInfo info = ChipmunkMod.CONFIG.bots.chomens;
|
||||
public static int chomens (final String command) throws RuntimeException {
|
||||
final Configuration.BotInfo info = ChipmunkMod.CONFIG.bots.chomens;
|
||||
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
|
@ -125,24 +126,25 @@ public class BotValidationUtilities {
|
|||
|
||||
final String prefix = info.prefix;
|
||||
final String key = info.key;
|
||||
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
if (key == null)
|
||||
throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
|
||||
try {
|
||||
String[] arguments = command.split(" ");
|
||||
final String[] arguments = command.split(" ");
|
||||
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
String time = String.valueOf(System.currentTimeMillis() / 5_000);
|
||||
String input = client.player.getUuidAsString() + arguments[0] + time + key;
|
||||
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
String stringHash = Hexadecimal.encode(hash).substring(0, 16);
|
||||
final MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
final String time = String.valueOf(System.currentTimeMillis() / 5_000);
|
||||
final String input = client.player.getUuidAsString() + arguments[0] + time + key;
|
||||
final byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
String stringHash = new String(Hex.encodeHex(hash)).substring(0, 16);
|
||||
|
||||
final boolean shouldSectionSign = CustomChat.INSTANCE.enabled && player.hasPermissionLevel(2) && player.isCreative();
|
||||
|
||||
if (shouldSectionSign) {
|
||||
stringHash = String.join("",
|
||||
Arrays.stream(stringHash.split(""))
|
||||
.map((letter) -> "§" + letter)
|
||||
.toArray(String[]::new)
|
||||
Arrays.stream(stringHash.split(""))
|
||||
.map((letter) -> "§" + letter)
|
||||
.toArray(String[]::new)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -157,68 +159,43 @@ public class BotValidationUtilities {
|
|||
String.join(" ", restArguments);
|
||||
|
||||
Chat.sendChatMessage(toSend);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int fnfboyfriend (String command) {
|
||||
try {
|
||||
final String prefix = ChipmunkMod.CONFIG.bots.fnfboyfriend.prefix;
|
||||
|
||||
String[] arguments = command.split(" ");
|
||||
|
||||
long currentTime = System.currentTimeMillis() / 1000;
|
||||
final String key = ChipmunkMod.CONFIG.bots.fnfboyfriend.key;
|
||||
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
String input = currentTime + key;
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
byte[] hash = digest.digest(input.getBytes());
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte b : hash) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) hexString.append('0');
|
||||
hexString.append(hex);
|
||||
}
|
||||
|
||||
final String[] restArguments = Arrays.copyOfRange(arguments, 1, arguments.length);
|
||||
|
||||
final String result = hexString.substring(0, 16);
|
||||
|
||||
Chat.sendChatMessage(prefix + arguments[0] + " " + result + " " + String.join(" ", restArguments));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int nbot (String command) throws RuntimeException {
|
||||
public static int nbot (final String command) throws RuntimeException {
|
||||
final Configuration.BotInfo info = ChipmunkMod.CONFIG.bots.nbot;
|
||||
|
||||
final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
final String prefix = info.prefix;
|
||||
final String key = info.key;
|
||||
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
if (key == null)
|
||||
throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
|
||||
try {
|
||||
String[] arguments = command.split(" ");
|
||||
final String[] arguments = command.split(" ");
|
||||
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
final MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
|
||||
String time = String.valueOf(System.currentTimeMillis() / 5_000);
|
||||
String input = arguments[0].replaceAll("&[0-9a-fklmnor]", "") + ";" + client.player.getUuidAsString() + ";" + time + ";" + key;
|
||||
final long time = Math.floorDiv(System.currentTimeMillis(), 250);
|
||||
|
||||
md.update(input.getBytes(StandardCharsets.UTF_8));
|
||||
// yep it is very raw code indeed.
|
||||
final String input = "ThisCodeIsRaw;" + client.player.getUuidAsString() + ";" + time + ";" + key;
|
||||
|
||||
byte[] hash = md.digest();
|
||||
final byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
final byte[] positiveDigest = new byte[digest.length + 1];
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(hash, 0, 4);
|
||||
long bigInt = (buffer.getInt() & 0xFFFFFFFFL);;
|
||||
String stringHash = Long.toString(bigInt, 36);
|
||||
System.arraycopy(digest, 0, positiveDigest, 1, digest.length);
|
||||
|
||||
final BigInteger bi = new BigInteger(positiveDigest);
|
||||
|
||||
final String b36 = bi.toString(36);
|
||||
|
||||
final String stringHash = b36.length() > 16 ? b36.substring(0, 16) : b36;
|
||||
|
||||
final String[] restArguments = Arrays.copyOfRange(arguments, 1, arguments.length);
|
||||
|
||||
|
@ -230,31 +207,32 @@ public class BotValidationUtilities {
|
|||
String.join(" ", restArguments);
|
||||
|
||||
Chat.sendChatMessage(toSend, true);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
public static int kittycorp (String command) throws RuntimeException {
|
||||
public static int kittycorp (final String command) throws RuntimeException {
|
||||
final Configuration.BotInfo info = ChipmunkMod.CONFIG.bots.kittycorp;
|
||||
final ClientPlayNetworkHandler networkHandler = MinecraftClient.getInstance().getNetworkHandler();
|
||||
|
||||
final String prefix = info.prefix;
|
||||
final String key = info.key;
|
||||
if (key == null) throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
if (key == null)
|
||||
throw new RuntimeException("The key of the bot is unspecified (null), did you incorrectly add it to your config?");
|
||||
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
String time = String.valueOf(System.currentTimeMillis() / 10000);
|
||||
String input = prefix + command.replaceAll("&[0-9a-fklmnorx]", "") + ";" + time + ";" + key;
|
||||
byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
|
||||
String stringHash = bigInt.toString(Character.MAX_RADIX);
|
||||
final MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
final String time = String.valueOf(System.currentTimeMillis() / 10000);
|
||||
final String input = prefix + command.replaceAll("&[0-9a-fklmnorx]", "") + ";" + time + ";" + key;
|
||||
final byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
final BigInteger bigInt = new BigInteger(1, Arrays.copyOfRange(hash, 0, 4));
|
||||
final String stringHash = bigInt.toString(Character.MAX_RADIX);
|
||||
|
||||
Chat.sendChatMessage(prefix + command + " " + stringHash, true);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ package land.chipmunk.chipmunkmod.util;
|
|||
import java.awt.*;
|
||||
|
||||
public class ColorUtilities {
|
||||
public static int hsvToRgb (int hue, int saturation, int value) {
|
||||
Color color = Color.getHSBColor(hue / 360.0f, saturation / 100.0f, value / 100.0f);
|
||||
public static int hsvToRgb (final int hue, final int saturation, final int value) {
|
||||
final Color color = Color.getHSBColor(hue / 360.0f, saturation / 100.0f, value / 100.0f);
|
||||
return color.getRGB() & 0xFFFFFF;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.util;
|
||||
|
||||
import land.chipmunk.chipmunkmod.ChipmunkMod;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Debug {
|
||||
public static ArrayList<String> known = new ArrayList<>();
|
||||
public static ArrayList<String> selected = new ArrayList<>();
|
||||
public static void debug(String string, String caller) {
|
||||
if(selected.contains(caller)) ChipmunkMod.LOGGER.info(String.format("[DEBUG|%s] %s", caller, string));
|
||||
if(!known.contains(caller)) known.add(caller);
|
||||
}
|
||||
}
|
|
@ -14,46 +14,48 @@ import java.security.cert.X509Certificate;
|
|||
|
||||
public class DownloadUtilities {
|
||||
|
||||
private static class DefaultTrustManager implements X509TrustManager {
|
||||
public static byte[] DownloadToByteArray (final URL url) throws IOException, KeyManagementException, NoSuchAlgorithmException {
|
||||
final SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
ctx.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() }, new SecureRandom());
|
||||
SSLContext.setDefault(ctx);
|
||||
final URLConnection conn = url.openConnection();
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(10000);
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.4; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0");
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] arg0, String arg1) {}
|
||||
try (final BufferedInputStream downloadStream = new BufferedInputStream(conn.getInputStream())) {
|
||||
final ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
|
||||
final byte[] buf = new byte[1024];
|
||||
int n;
|
||||
while ((n = downloadStream.read(buf)) > 0) {
|
||||
byteArrayStream.write(buf, 0, n);
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] arg0, String arg1) {}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DownloadToByteArray(URL url) throws IOException, KeyManagementException, NoSuchAlgorithmException {
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
|
||||
SSLContext.setDefault(ctx);
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setConnectTimeout(5000);
|
||||
conn.setReadTimeout(10000);
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0");
|
||||
|
||||
try (BufferedInputStream downloadStream = new BufferedInputStream(conn.getInputStream())) {
|
||||
ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
|
||||
byte[] buf = new byte[1024];
|
||||
int n;
|
||||
while ((n = downloadStream.read(buf)) > 0) {
|
||||
byteArrayStream.write(buf, 0, n);
|
||||
|
||||
if (Thread.interrupted()) {
|
||||
return null;
|
||||
if (Thread.interrupted()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return byteArrayStream.toByteArray();
|
||||
}
|
||||
}
|
||||
return byteArrayStream.toByteArray();
|
||||
// Closing a ByteArrayInputStream has no effect, so I do not close it.
|
||||
}
|
||||
// Closing a ByteArrayInputStream has no effect, so I do not close it.
|
||||
}
|
||||
|
||||
public static InputStream DownloadToInputStream(URL url) throws KeyManagementException, NoSuchAlgorithmException, IOException {
|
||||
return new ByteArrayInputStream(DownloadToByteArray(url));
|
||||
}
|
||||
public static InputStream DownloadToInputStream (final URL url) throws KeyManagementException, NoSuchAlgorithmException, IOException {
|
||||
return new ByteArrayInputStream(DownloadToByteArray(url));
|
||||
}
|
||||
|
||||
private static class DefaultTrustManager implements X509TrustManager {
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted (final X509Certificate[] arg0, final String arg1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted (final X509Certificate[] arg0, final String arg1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers () {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.util;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class Executor {
|
||||
public static ExecutorService service = Executors.newFixedThreadPool(20);
|
||||
public static ExecutorService antiChatSpamService = Executors.newFixedThreadPool(1);
|
||||
public static Future<?> submit(Runnable runnable) {
|
||||
return service.submit(runnable);
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package land.chipmunk.chipmunkmod.util;
|
||||
|
||||
public interface Hexadecimal {
|
||||
static String encode (byte b) {
|
||||
return "" + Character.forDigit((b >> 4) & 0xF, 16) + Character.forDigit((b & 0xF), 16);
|
||||
}
|
||||
|
||||
static String encode (byte[] array) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < array.length; i++) sb.append(encode(array[i]));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// TODO: Decode
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue