mirror of
https://github.com/Shiewk/Widgets.git
synced 2026-04-28 11:34:17 +02:00
Initial Commit (1.0)
This commit is contained in:
+63
@@ -0,0 +1,63 @@
|
|||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
out/
|
||||||
|
.idea_modules/
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.ctxt
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
hs_err_pid*
|
||||||
|
*~
|
||||||
|
.fuse_hidden*
|
||||||
|
.directory
|
||||||
|
.Trash-*
|
||||||
|
.nfs*
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
Icon
|
||||||
|
._*
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
*.stackdump
|
||||||
|
[Dd]esktop.ini
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
*.lnk
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
gradle-app.setting
|
||||||
|
.gradletasknamecache
|
||||||
|
**/build/
|
||||||
|
run/
|
||||||
|
!gradle-wrapper.jar
|
||||||
|
gradle/
|
||||||
|
gradlew
|
||||||
|
gradlew.bat
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Widgets
|
||||||
|
**Adds customizable in-game widgets to your game.**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This Minecraft mod adds customizable widgets that you may know from other Minecraft clients.
|
||||||
|
|
||||||
|
This mod was specifically made for people who just use Fabric or Quilt (and no specific client).
|
||||||
|
It also has some benefits over using clients:
|
||||||
|
1. Performance:
|
||||||
|
- We've tried to optimize the mod as much as possible to make sure the game runs as smoothly as possible.
|
||||||
|
- Disabled widgets don't use any performance
|
||||||
|
2. No additional features
|
||||||
|
- The mod focuses on **widgets only**. It does not contain any other features such as performance improvements or mods.
|
||||||
|
3. Easy to use
|
||||||
|
- We've tried to make the mod as easy to use as possible, for example, there are three ways to open the config menu instead of only a keybind.
|
||||||
|
|
||||||
|
## Widget settings
|
||||||
|
There are three ways to open the widget settings:
|
||||||
|
1. Press the key bind (bound to right shift by default)
|
||||||
|
2. Enter the command "/widgetsmod"
|
||||||
|
3. Open the config menu through [Mod Menu](https://modrinth.com/mod/modmenu)
|
||||||
|
|
||||||
|
Once you've opened the settings, you will see something like this:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
You can now enable the widgets you want to enable, or click on them to view their additional settings, as you can see here:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
When you're done with configuring which widgets you want to enable and their settings, click the "Edit Layout" button in the bottom right corner.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
This will take you to a screen where you can freely move around your enabled widgets.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
When you're done, just press Escape until you return to the game.
|
||||||
|
|
||||||
|
Now, everything is done. Your widgets automatically save for the next time you play.
|
||||||
+106
@@ -0,0 +1,106 @@
|
|||||||
|
plugins {
|
||||||
|
id 'fabric-loom' version '1.6-SNAPSHOT'
|
||||||
|
id 'maven-publish'
|
||||||
|
}
|
||||||
|
|
||||||
|
version = project.mod_version
|
||||||
|
group = project.maven_group
|
||||||
|
|
||||||
|
base {
|
||||||
|
archivesName = project.archives_base_name
|
||||||
|
}
|
||||||
|
|
||||||
|
loom {
|
||||||
|
accessWidenerPath = file("src/main/resources/widgets.accesswidener")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
// Add repositories to retrieve artifacts from in here.
|
||||||
|
// You should only use this when depending on other mods because
|
||||||
|
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||||
|
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||||
|
// for more information about repositories.
|
||||||
|
exclusiveContent {
|
||||||
|
forRepository {
|
||||||
|
maven {
|
||||||
|
name = "Modrinth"
|
||||||
|
url = "https://api.modrinth.com/maven"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filter {
|
||||||
|
includeGroup "maven.modrinth"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// To change the versions see the gradle.properties file
|
||||||
|
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||||
|
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.
|
||||||
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||||
|
modImplementation "maven.modrinth:modmenu:11.0.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
inputs.property "version", project.version
|
||||||
|
inputs.property "minecraft_version", project.minecraft_version
|
||||||
|
inputs.property "loader_version", project.loader_version
|
||||||
|
filteringCharset "UTF-8"
|
||||||
|
|
||||||
|
filesMatching("fabric.mod.json") {
|
||||||
|
expand "version": project.version,
|
||||||
|
"minecraft_version": project.minecraft_version,
|
||||||
|
"loader_version": project.loader_version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def targetJavaVersion = 21
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
||||||
|
// this fixes some edge cases with special characters not displaying correctly
|
||||||
|
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
||||||
|
// If Javadoc is generated, this must be specified in that task too.
|
||||||
|
it.options.encoding = "UTF-8"
|
||||||
|
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
|
||||||
|
it.options.release.set(targetJavaVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||||
|
if (JavaVersion.current() < javaVersion) {
|
||||||
|
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
||||||
|
}
|
||||||
|
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
||||||
|
// if it is present.
|
||||||
|
// If you remove this line, sources will not be generated.
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
from("LICENSE") {
|
||||||
|
rename { "${it}_${project.archivesBaseName}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure the maven publication
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
create("mavenJava", MavenPublication) {
|
||||||
|
artifactId = project.archives_base_name
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||||
|
repositories {
|
||||||
|
// Add repositories to publish to here.
|
||||||
|
// Notice: This block does NOT have the same function as the block in the top level.
|
||||||
|
// The repositories here will be used for publishing your artifact, not for
|
||||||
|
// retrieving dependencies.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Done to increase the memory available to gradle.
|
||||||
|
org.gradle.jvmargs=-Xmx1G
|
||||||
|
# Fabric Properties
|
||||||
|
# check these on https://modmuss50.me/fabric.html
|
||||||
|
minecraft_version=1.21
|
||||||
|
yarn_mappings=1.21+build.9
|
||||||
|
loader_version=0.16.2
|
||||||
|
# Mod Properties
|
||||||
|
mod_version=1.0
|
||||||
|
maven_group=de.shiewk
|
||||||
|
archives_base_name=Widgets
|
||||||
|
# Dependencies
|
||||||
|
# check this on https://modmuss50.me/fabric.html
|
||||||
|
fabric_version=0.101.2+1.21
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = 'Fabric'
|
||||||
|
url = 'https://maven.fabricmc.net/'
|
||||||
|
}
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package de.shiewk.widgets;
|
||||||
|
|
||||||
|
public interface Dimensionable {
|
||||||
|
int width();
|
||||||
|
int height();
|
||||||
|
double getX(int mx);
|
||||||
|
double getY(int my);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package de.shiewk.widgets;
|
||||||
|
|
||||||
|
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||||
|
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||||
|
import de.shiewk.widgets.client.screen.WidgetConfigScreen;
|
||||||
|
|
||||||
|
public class ModMenuConfig implements ModMenuApi {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigScreenFactory<?> getModConfigScreenFactory() {
|
||||||
|
return WidgetConfigScreen::new;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package de.shiewk.widgets;
|
||||||
|
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public abstract class ModWidget implements Dimensionable {
|
||||||
|
|
||||||
|
private final Identifier id;
|
||||||
|
private final WidgetSettings settings;
|
||||||
|
|
||||||
|
protected ModWidget(Identifier id, List<WidgetSettingOption> customSettings) {
|
||||||
|
Objects.requireNonNull(id, "id");
|
||||||
|
this.id = id;
|
||||||
|
this.settings = WidgetSettings.ofId(id, customSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Identifier getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final WidgetSettings getSettings() {
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
public abstract void render(DrawContext context, long measuringTimeNano, TextRenderer textRenderer, int posX, int posY);
|
||||||
|
public abstract void tick();
|
||||||
|
public abstract Text getName();
|
||||||
|
public abstract Text getDescription();
|
||||||
|
public abstract void onSettingsChanged(WidgetSettings settings);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getX(int mx) {
|
||||||
|
return (int) WidgetUtils.translateToScreen(settings.posX, mx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getY(int my) {
|
||||||
|
return (int) WidgetUtils.translateToScreen(settings.posY, my);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package de.shiewk.widgets;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import net.minecraft.client.gui.Drawable;
|
||||||
|
import net.minecraft.client.gui.widget.ClickableWidget;
|
||||||
|
import net.minecraft.client.gui.widget.Widget;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public abstract class WidgetSettingOption implements Drawable, Widget {
|
||||||
|
private final String id;
|
||||||
|
private final Text name;
|
||||||
|
private int x = 0;
|
||||||
|
private int y = 0;
|
||||||
|
private boolean focused = false;
|
||||||
|
|
||||||
|
protected WidgetSettingOption(String id, Text name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Text getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract JsonElement saveState();
|
||||||
|
public abstract void loadState(JsonElement state);
|
||||||
|
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int button){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean charTyped(char chr, int modifiers) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setX(int x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setY(int y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void forEachChild(Consumer<ClickableWidget> consumer) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFocused() {
|
||||||
|
return focused;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFocused(boolean focused) {
|
||||||
|
this.focused = focused;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package de.shiewk.widgets;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import de.shiewk.widgets.client.WidgetManager;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static de.shiewk.widgets.WidgetUtils.translateToWidgetSettingsValue;
|
||||||
|
import static de.shiewk.widgets.WidgetsMod.LOGGER;
|
||||||
|
|
||||||
|
public class WidgetSettings {
|
||||||
|
public double posX = 0; // posx * 100 = screen width
|
||||||
|
public double posY = 0; // posy * 100 = screen height
|
||||||
|
private boolean enabled = false;
|
||||||
|
private final ObjectArrayList<WidgetSettingOption> customSettings;
|
||||||
|
|
||||||
|
private WidgetSettings(JsonObject data, List<WidgetSettingOption> settings){
|
||||||
|
customSettings = new ObjectArrayList<>(settings);
|
||||||
|
if (data != null){
|
||||||
|
final JsonElement enabled = data.get("enabled");
|
||||||
|
this.enabled = enabled.isJsonPrimitive() && enabled.getAsJsonPrimitive().isBoolean() && enabled.getAsBoolean();
|
||||||
|
final JsonElement x = data.get("x");
|
||||||
|
this.posX = x.isJsonPrimitive() ? x.getAsJsonPrimitive().isNumber() ? x.getAsDouble() : 0 : 0;
|
||||||
|
final JsonElement y = data.get("y");
|
||||||
|
this.posY = y.isJsonPrimitive() ? y.getAsJsonPrimitive().isNumber() ? y.getAsDouble() : 0 : 0;
|
||||||
|
final JsonElement s = data.get("settings");
|
||||||
|
if (s != null && s.isJsonObject()){
|
||||||
|
final JsonObject savedSettings = s.getAsJsonObject();
|
||||||
|
for (WidgetSettingOption setting : this.customSettings) {
|
||||||
|
final String settingId = setting.getId();
|
||||||
|
if (savedSettings.has(settingId)){
|
||||||
|
try {
|
||||||
|
setting.loadState(savedSettings.get(settingId));
|
||||||
|
} catch (Throwable e){
|
||||||
|
LOGGER.error("Could not load setting '{}' from element {}:", settingId, savedSettings.get(settingId));
|
||||||
|
LOGGER.error(e.toString());
|
||||||
|
for (StackTraceElement element : e.getStackTrace()) {
|
||||||
|
LOGGER.error(element.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static WidgetSettings ofId(Identifier id, List<WidgetSettingOption> customSettings){
|
||||||
|
final JsonObject data = WidgetManager.loadWidget(id);
|
||||||
|
return new WidgetSettings(data, customSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosX(double v, int widgetWidth, int maxWidth) {
|
||||||
|
posX = MathHelper.clamp(v, 0, 100 - translateToWidgetSettingsValue(widgetWidth, maxWidth));
|
||||||
|
}
|
||||||
|
public void setPosY(double v, int widgetHeight, int maxHeight) {
|
||||||
|
posY = MathHelper.clamp(v, 0, 100 - translateToWidgetSettingsValue(widgetHeight, maxHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled(){
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(ModWidget widget, boolean enabled){
|
||||||
|
this.enabled = enabled;
|
||||||
|
if (enabled){
|
||||||
|
WidgetManager.enable(widget);
|
||||||
|
} else {
|
||||||
|
WidgetManager.disable(widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleEnabled(ModWidget widget){
|
||||||
|
setEnabled(widget, !enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final JsonObject saveState(){
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
object.addProperty("x", posX);
|
||||||
|
object.addProperty("y", posY);
|
||||||
|
object.addProperty("enabled", enabled);
|
||||||
|
JsonObject customSettings = new JsonObject();
|
||||||
|
for (WidgetSettingOption customSetting : this.customSettings) {
|
||||||
|
customSettings.add(customSetting.getId(), customSetting.saveState());
|
||||||
|
}
|
||||||
|
object.add("settings", customSettings);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WidgetSettingOption optionById(String id){
|
||||||
|
for (WidgetSettingOption customSetting : customSettings) {
|
||||||
|
if (customSetting.getId().equals(id)){
|
||||||
|
return customSetting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectArrayList<WidgetSettingOption> getCustomSettings() {
|
||||||
|
return customSettings.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package de.shiewk.widgets;
|
||||||
|
|
||||||
|
public class WidgetUtils {
|
||||||
|
|
||||||
|
public static double translateToWidgetSettingsValue(double value, int max){
|
||||||
|
return (value / max) * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double translateToScreen(double value, int max){
|
||||||
|
return value / 100d * max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double computeEasing(double x) {
|
||||||
|
return 1d - Math.pow(1d - x, 3.5d);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package de.shiewk.widgets;
|
||||||
|
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class WidgetsMod implements ModInitializer {
|
||||||
|
public static final Logger LOGGER = LoggerFactory.getLogger("Widgets");
|
||||||
|
public static final String MOD_ID = "widgets";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package de.shiewk.widgets.client;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.internal.Streams;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import de.shiewk.widgets.ModWidget;
|
||||||
|
import de.shiewk.widgets.WidgetsMod;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class WidgetManager {
|
||||||
|
|
||||||
|
static final ObjectArrayList<ModWidget> enabled = new ObjectArrayList<>(); // for performance
|
||||||
|
private static final ObjectArrayList<ModWidget> allWidgets = new ObjectArrayList<>();
|
||||||
|
|
||||||
|
public static void register(ModWidget widget){
|
||||||
|
allWidgets.add(widget);
|
||||||
|
if (widget.getSettings().isEnabled()){
|
||||||
|
enable(widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectArrayList<ModWidget> getEnabledWidgets() {
|
||||||
|
return new ObjectArrayList<>(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectArrayList<ModWidget> getAllWidgets() {
|
||||||
|
return new ObjectArrayList<>(allWidgets);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void enable(ModWidget widget) {
|
||||||
|
enabled.add(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void disable(ModWidget widget) {
|
||||||
|
enabled.remove(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Function<Identifier, File> saveFileFactory;
|
||||||
|
private static final Gson gson = new Gson();
|
||||||
|
|
||||||
|
public static void saveWidgets(List<ModWidget> widgets) {
|
||||||
|
for (ModWidget widget : widgets) {
|
||||||
|
WidgetsMod.LOGGER.info("Saving widget {}", widget.getId());
|
||||||
|
final File saveFile = saveFileFactory.apply(widget.getId());
|
||||||
|
try {
|
||||||
|
if (saveFile.getParentFile().isDirectory() || saveFile.getParentFile().mkdirs()){
|
||||||
|
if (saveFile.isFile() || saveFile.createNewFile()){
|
||||||
|
try (FileWriter fw = new FileWriter(saveFile)){
|
||||||
|
try (JsonWriter jw = new JsonWriter(fw)){
|
||||||
|
Streams.write(widget.getSettings().saveState(), jw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WidgetsMod.LOGGER.error("Could not create file: {}", saveFile.getPath());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WidgetsMod.LOGGER.error("Could not create directory: {}", saveFile.getParentFile().getPath());
|
||||||
|
}
|
||||||
|
} catch (IOException e){
|
||||||
|
WidgetsMod.LOGGER.error("An I/O operation failed while saving widget {} ({})", widget, widget.getId());
|
||||||
|
WidgetsMod.LOGGER.error(e.toString());
|
||||||
|
for (StackTraceElement element : e.getStackTrace()) {
|
||||||
|
WidgetsMod.LOGGER.error(String.valueOf(element));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable JsonObject loadWidget(Identifier id) {
|
||||||
|
WidgetsMod.LOGGER.info("Loading widget data of {}", id);
|
||||||
|
final File saveFile = saveFileFactory.apply(id);
|
||||||
|
if (!saveFile.isFile()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
try (FileReader fr = new FileReader(saveFile)){
|
||||||
|
return gson.fromJson(fr, JsonObject.class);
|
||||||
|
}
|
||||||
|
} catch (IOException e){
|
||||||
|
WidgetsMod.LOGGER.error("An I/O operation failed while loading widget {}", id);
|
||||||
|
WidgetsMod.LOGGER.error(e.toString());
|
||||||
|
for (StackTraceElement element : e.getStackTrace()) {
|
||||||
|
WidgetsMod.LOGGER.error(String.valueOf(element));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package de.shiewk.widgets.client;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.ModWidget;
|
||||||
|
import de.shiewk.widgets.WidgetSettings;
|
||||||
|
import de.shiewk.widgets.client.screen.EditWidgetPositionsScreen;
|
||||||
|
import de.shiewk.widgets.client.screen.WidgetConfigScreen;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.render.RenderTickCounter;
|
||||||
|
import net.minecraft.util.Util;
|
||||||
|
import net.minecraft.util.profiler.Profiler;
|
||||||
|
|
||||||
|
import static de.shiewk.widgets.WidgetUtils.translateToScreen;
|
||||||
|
|
||||||
|
public class WidgetRenderer implements HudRenderCallback, ClientTickEvents.StartTick, ClientLifecycleEvents.ClientStarted {
|
||||||
|
|
||||||
|
private static MinecraftClient client;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHudRender(DrawContext drawContext, RenderTickCounter tickCounter) {
|
||||||
|
if (client.options.hudHidden) return;
|
||||||
|
if (client.currentScreen instanceof EditWidgetPositionsScreen) return;
|
||||||
|
final Profiler profiler = client.getProfiler();
|
||||||
|
profiler.push("widgets");
|
||||||
|
final TextRenderer textRenderer = client.textRenderer;
|
||||||
|
final long timeNano = Util.getMeasuringTimeNano();
|
||||||
|
final int windowWidth = drawContext.getScaledWindowWidth();
|
||||||
|
final int windowHeight = drawContext.getScaledWindowHeight();
|
||||||
|
|
||||||
|
final ObjectArrayList<ModWidget> enabled = WidgetManager.enabled;
|
||||||
|
for (int i = 0, enabledSize = enabled.size(); i < enabledSize; i++) {
|
||||||
|
final ModWidget widget = enabled.get(i);
|
||||||
|
profiler.push(widget.getId().toString());
|
||||||
|
final WidgetSettings settings = widget.getSettings();
|
||||||
|
widget.render(
|
||||||
|
drawContext,
|
||||||
|
timeNano,
|
||||||
|
textRenderer,
|
||||||
|
(int) Math.round(Math.min(translateToScreen(settings.posX, windowWidth), windowWidth - widget.width())),
|
||||||
|
(int) Math.round(Math.min(translateToScreen(settings.posY, windowHeight), windowHeight - widget.height()))
|
||||||
|
);
|
||||||
|
profiler.pop();
|
||||||
|
}
|
||||||
|
profiler.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartTick(MinecraftClient client) {
|
||||||
|
final Profiler profiler = (WidgetRenderer.client = client).getProfiler();
|
||||||
|
profiler.push("widgets");
|
||||||
|
|
||||||
|
final ObjectArrayList<ModWidget> enabled = WidgetManager.enabled;
|
||||||
|
for (int i = 0, enabledSize = enabled.size(); i < enabledSize; i++) {
|
||||||
|
final ModWidget widget = enabled.get(i);
|
||||||
|
profiler.push(widget.getId().toString());
|
||||||
|
widget.tick();
|
||||||
|
profiler.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
profiler.pop();
|
||||||
|
|
||||||
|
if (WidgetsModClient.configKeyBinding.wasPressed()){
|
||||||
|
client.setScreen(new WidgetConfigScreen(client.currentScreen));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClientStarted(MinecraftClient client) {
|
||||||
|
for (ModWidget widget : WidgetManager.getAllWidgets()) {
|
||||||
|
widget.onSettingsChanged(widget.getSettings());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package de.shiewk.widgets.client;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.WidgetsMod;
|
||||||
|
import de.shiewk.widgets.client.screen.WidgetConfigScreen;
|
||||||
|
import de.shiewk.widgets.widgets.*;
|
||||||
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
|
||||||
|
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||||
|
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.option.KeyBinding;
|
||||||
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class WidgetsModClient implements ClientModInitializer {
|
||||||
|
|
||||||
|
static KeyBinding configKeyBinding;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeClient() {
|
||||||
|
HudRenderCallback.EVENT.register(new WidgetRenderer());
|
||||||
|
ClientTickEvents.START_CLIENT_TICK.register(new WidgetRenderer());
|
||||||
|
ClientLifecycleEvents.CLIENT_STARTED.register(new WidgetRenderer());
|
||||||
|
|
||||||
|
// manage widgets keybind
|
||||||
|
configKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
"widgets.key.config",
|
||||||
|
InputUtil.Type.KEYSYM,
|
||||||
|
GLFW.GLFW_KEY_RIGHT_SHIFT,
|
||||||
|
"widgets.key.category"
|
||||||
|
));
|
||||||
|
|
||||||
|
// in-game /widgetsmod command
|
||||||
|
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) ->
|
||||||
|
dispatcher.register(ClientCommandManager.literal("widgetsmod").executes(ctx -> {
|
||||||
|
WidgetsMod.LOGGER.info("Ran in-game command");
|
||||||
|
final MinecraftClient client = ctx.getSource().getClient();
|
||||||
|
client.send(() -> client.setScreen(new WidgetConfigScreen(client.currentScreen)));
|
||||||
|
return 0;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
WidgetManager.saveFileFactory = id -> new File(MinecraftClient.getInstance().runDirectory.getPath() + "/config/widgets/" + id.getNamespace() + "/" + id.getPath() + ".json");
|
||||||
|
|
||||||
|
WidgetManager.register(new FPSWidget(Identifier.of(WidgetsMod.MOD_ID, "fps")));
|
||||||
|
WidgetManager.register(new ClockWidget(Identifier.of(WidgetsMod.MOD_ID, "clock")));
|
||||||
|
WidgetManager.register(new CoordinatesWidget(Identifier.of(WidgetsMod.MOD_ID, "coordinates")));
|
||||||
|
WidgetManager.register(new BandwidthWidget(Identifier.of(WidgetsMod.MOD_ID, "bandwidth")));
|
||||||
|
WidgetManager.register(new PingWidget(Identifier.of(WidgetsMod.MOD_ID, "ping")));
|
||||||
|
WidgetManager.register(new ServerIPWidget(Identifier.of(WidgetsMod.MOD_ID, "server_ip")));
|
||||||
|
WidgetManager.register(new PlayerCountWidget(Identifier.of(WidgetsMod.MOD_ID, "player_count")));
|
||||||
|
WidgetManager.register(new CPSWidget(Identifier.of(WidgetsMod.MOD_ID, "cps")));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package de.shiewk.widgets.client.screen;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.WidgetUtils;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Util;
|
||||||
|
|
||||||
|
public abstract class AnimatedScreen extends Screen {
|
||||||
|
protected final Screen parent;
|
||||||
|
private final int animationDurationMs;
|
||||||
|
private final long creationTime = Util.getMeasuringTimeNano();
|
||||||
|
protected AnimatedScreen(Text title, Screen parent, int animationDurationMs) {
|
||||||
|
super(title);
|
||||||
|
this.parent = parent;
|
||||||
|
this.animationDurationMs = animationDurationMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
double timeMs = (Util.getMeasuringTimeNano() - creationTime) / 1000000d;
|
||||||
|
final boolean shouldAnimate = timeMs < animationDurationMs;
|
||||||
|
if (shouldAnimate){
|
||||||
|
double translation = WidgetUtils.computeEasing(timeMs / animationDurationMs) * this.width;
|
||||||
|
context.getMatrices().push();
|
||||||
|
context.getMatrices().translate(-translation, 0, 0);
|
||||||
|
parent.render(context, (int) (mouseX + translation), mouseY, delta);
|
||||||
|
context.getMatrices().translate(this.width, 0, 0);
|
||||||
|
mouseX -= (int) translation;
|
||||||
|
}
|
||||||
|
super.render(context, mouseX, mouseY, delta);
|
||||||
|
this.renderScreenContents(context, mouseX, mouseY, delta);
|
||||||
|
if (shouldAnimate){
|
||||||
|
context.getMatrices().pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void renderScreenContents(DrawContext context, int mouseX, int mouseY, float delta);
|
||||||
|
}
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
package de.shiewk.widgets.client.screen;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.Dimensionable;
|
||||||
|
import de.shiewk.widgets.ModWidget;
|
||||||
|
import de.shiewk.widgets.WidgetSettings;
|
||||||
|
import de.shiewk.widgets.client.WidgetManager;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Util;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import static de.shiewk.widgets.WidgetUtils.translateToScreen;
|
||||||
|
import static de.shiewk.widgets.WidgetUtils.translateToWidgetSettingsValue;
|
||||||
|
|
||||||
|
public class EditWidgetPositionsScreen extends AnimatedScreen {
|
||||||
|
|
||||||
|
private record Alignment(int x, int y, int width, int height) implements Dimensionable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getX(int mx) {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getY(int my) {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Screen parent;
|
||||||
|
private final Consumer<ModWidget> onEdit;
|
||||||
|
private boolean alignX = true;
|
||||||
|
private boolean alignY = true;
|
||||||
|
public EditWidgetPositionsScreen(Screen parent, Consumer<ModWidget> onEdit) {
|
||||||
|
super(Text.translatable("widgets.ui.editPositions"), parent, 500);
|
||||||
|
this.parent = parent;
|
||||||
|
this.onEdit = onEdit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
assert client != null;
|
||||||
|
client.setScreen(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private record AlignResult(double result, boolean isEnd){}
|
||||||
|
|
||||||
|
private @Nullable AlignResult alignX(double x, int width, ModWidget widget){
|
||||||
|
double endX = x + width;
|
||||||
|
int factor = alignX ? 2 : 0;
|
||||||
|
for (Dimensionable rect : this.getAlignments(widget)) {
|
||||||
|
if (rect == widget) continue;
|
||||||
|
final double nwx = rect.getX(this.width);
|
||||||
|
final double nww = rect.width();
|
||||||
|
if (endX < nwx + factor && endX > nwx - factor){
|
||||||
|
return new AlignResult(nwx - width, true);
|
||||||
|
} else if (x < nwx + factor && x > nwx - factor){
|
||||||
|
return new AlignResult(nwx, false);
|
||||||
|
} else if (endX < nwx+nww + factor && endX > nwx + nww - factor){
|
||||||
|
return new AlignResult(nwx + nww - width, true);
|
||||||
|
} else if (x < nwx+nww + factor && x > nwx + nww - factor){
|
||||||
|
return new AlignResult(nwx + nww, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterable<? extends Dimensionable> getAlignments(Dimensionable rel) {
|
||||||
|
ObjectArrayList<Dimensionable> alignments = new ObjectArrayList<>();
|
||||||
|
for (ModWidget widget : WidgetManager.getEnabledWidgets()) {
|
||||||
|
alignments.add(widget);
|
||||||
|
}
|
||||||
|
alignments.add(new Alignment(2, 2, this.width / 2 - 2, this.height / 2 - 2));
|
||||||
|
alignments.add(new Alignment(this.width / 2, this.height / 2, this.width / 2 - 2, this.height / 2 - 2));
|
||||||
|
alignments.add(new Alignment(2, this.height / 2, this.width / 2 - 2, this.height / 2 - 2));
|
||||||
|
alignments.add(new Alignment(this.width / 2, 2, this.width / 2 - 2, this.height / 2 - 2));
|
||||||
|
alignments.add(new Alignment(this.width / 2 - rel.width() / 2, this.height / 2 - rel.height() / 2, rel.width(), rel.height()));
|
||||||
|
return alignments;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private @Nullable AlignResult alignY(double y, int height, ModWidget widget){
|
||||||
|
double endY = y + height;
|
||||||
|
int factor = alignY ? 2 : 0;
|
||||||
|
for (Dimensionable rect : this.getAlignments(widget)) {
|
||||||
|
if (rect == widget) continue;
|
||||||
|
final double nwy = rect.getY(this.height);
|
||||||
|
final double nwh = rect.height();
|
||||||
|
if (endY < nwy + factor && endY > nwy - factor){
|
||||||
|
return new AlignResult(nwy - height, true);
|
||||||
|
} else if (y < nwy + factor && y > nwy - factor){
|
||||||
|
return new AlignResult(nwy, false);
|
||||||
|
} else if (endY < nwy+nwh + factor && endY > nwy + nwh - factor){
|
||||||
|
return new AlignResult(nwy + nwh - height, true);
|
||||||
|
} else if (y < nwy+nwh + factor && y > nwy + nwh - factor){
|
||||||
|
return new AlignResult(nwy + nwh, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int SELECT_COLOR = Color.GREEN.getRGB(), ALIGN_COLOR = Color.ORANGE.getRGB(), ALIGN_DISABLED_COLOR = Color.GRAY.getRGB();
|
||||||
|
private ModWidget selectedWidget = null;
|
||||||
|
private ModWidget hoveredWidget = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderScreenContents(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
assert client != null;
|
||||||
|
for (ModWidget widget : WidgetManager.getEnabledWidgets()) {
|
||||||
|
final WidgetSettings settings = widget.getSettings();
|
||||||
|
final int ww = widget.width();
|
||||||
|
double wx = Math.min(translateToScreen(settings.posX, this.width), this.width - ww);
|
||||||
|
final int wh = widget.height();
|
||||||
|
double wy = Math.min(translateToScreen(settings.posY, this.height), this.height - wh);
|
||||||
|
if (selectedWidget == widget){
|
||||||
|
final AlignResult alignedX = alignX(wx, ww, widget);
|
||||||
|
if (alignedX != null){
|
||||||
|
context.drawVerticalLine((int) (!alignedX.isEnd() ? alignedX.result() : alignedX.result() + ww), 0, this.height, alignX ? ALIGN_COLOR : ALIGN_DISABLED_COLOR);
|
||||||
|
wx = alignedX.result();
|
||||||
|
}
|
||||||
|
final AlignResult alignedY = alignY(wy, wh, widget);
|
||||||
|
if (alignedY != null){
|
||||||
|
context.drawHorizontalLine(0, this.width, (int) (!alignedY.isEnd() ? alignedY.result() : alignedY.result() + wh), alignY ? ALIGN_COLOR : ALIGN_DISABLED_COLOR);
|
||||||
|
wy = alignedY.result();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hoveredWidget == null || hoveredWidget == widget){
|
||||||
|
if (mouseX <= wx + ww && mouseX >= wx && mouseY <= wy + wh && mouseY >= wy){
|
||||||
|
if (hoveredWidget == null){
|
||||||
|
hoveredWidget = widget;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hoveredWidget = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedWidget == null ? hoveredWidget == widget : selectedWidget == widget){
|
||||||
|
context.drawBorder((int) Math.round(wx-1), (int) Math.round(wy-1), ww+2, wh+2, SELECT_COLOR);
|
||||||
|
context.drawBorder((int) Math.round(wx), (int) Math.round(wy), ww, wh, SELECT_COLOR);
|
||||||
|
}
|
||||||
|
widget.render(context, Util.getMeasuringTimeNano(), textRenderer, (int) Math.round(wx), (int) Math.round(wy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||||
|
if (button == 0 && selectedWidget != null){
|
||||||
|
final AlignResult alignedX = alignX(translateToScreen(selectedWidget.getSettings().posX, this.width), selectedWidget.width(), selectedWidget);
|
||||||
|
if (alignedX != null){
|
||||||
|
selectedWidget.getSettings().setPosX(translateToWidgetSettingsValue(alignedX.result(), this.width), selectedWidget.width(), this.width);
|
||||||
|
}
|
||||||
|
final AlignResult alignedY = alignY(translateToScreen(selectedWidget.getSettings().posY, this.height), selectedWidget.height(), selectedWidget);
|
||||||
|
if (alignedY != null){
|
||||||
|
selectedWidget.getSettings().setPosY(translateToWidgetSettingsValue(alignedY.result(), this.height), selectedWidget.height(), this.height);
|
||||||
|
}
|
||||||
|
onEdit.accept(selectedWidget);
|
||||||
|
selectedWidget = null;
|
||||||
|
}
|
||||||
|
return super.mouseReleased(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
if (button == 0 && hoveredWidget != null){
|
||||||
|
selectedWidget = hoveredWidget;
|
||||||
|
}
|
||||||
|
return super.mouseClicked(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
|
||||||
|
if (button == 0){
|
||||||
|
assert client != null;
|
||||||
|
final ModWidget widget = selectedWidget;
|
||||||
|
if (widget != null){
|
||||||
|
final WidgetSettings settings = widget.getSettings();
|
||||||
|
final int ww = widget.width();
|
||||||
|
final int wx = (int) Math.min(translateToScreen(settings.posX, this.width), this.width - ww);
|
||||||
|
final int wh = widget.height();
|
||||||
|
final int wy = (int) Math.min(translateToScreen(settings.posY, this.height), this.height - wh);
|
||||||
|
if (mouseX <= wx + ww + deltaX && mouseX >= wx + deltaX){
|
||||||
|
if (mouseY <= wy + wh + deltaY && mouseY >= wy + deltaY){
|
||||||
|
double newPosX = settings.posX + translateToWidgetSettingsValue(deltaX, this.width);
|
||||||
|
double newPosY = settings.posY + translateToWidgetSettingsValue(deltaY, this.height);
|
||||||
|
settings.setPosX(newPosX, ww, this.width);
|
||||||
|
settings.setPosY(newPosY, wh, this.height);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package de.shiewk.widgets.client.screen;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.ModWidget;
|
||||||
|
import de.shiewk.widgets.WidgetUtils;
|
||||||
|
import de.shiewk.widgets.client.WidgetManager;
|
||||||
|
import de.shiewk.widgets.client.screen.components.WidgetListWidget;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.widget.AxisGridWidget;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class WidgetConfigScreen extends Screen {
|
||||||
|
|
||||||
|
private final Screen parent;
|
||||||
|
private final long creationTime = Util.getMeasuringTimeNano();
|
||||||
|
private String search = "";
|
||||||
|
private WidgetListWidget widgetList = null;
|
||||||
|
private final ArrayList<ModWidget> widgetsEdited = new ArrayList<>();
|
||||||
|
private final Consumer<ModWidget> onWidgetEdit = this::changedSettings;
|
||||||
|
|
||||||
|
private double getScreenTimeMs(){
|
||||||
|
return (Util.getMeasuringTimeNano() - creationTime) / 1000000d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WidgetConfigScreen(Screen parent) {
|
||||||
|
super(Text.translatable("widgets.ui.config"));
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
WidgetManager.saveWidgets(widgetsEdited);
|
||||||
|
for (ModWidget widget : widgetsEdited) {
|
||||||
|
widget.onSettingsChanged(widget.getSettings());
|
||||||
|
}
|
||||||
|
assert client != null;
|
||||||
|
client.setScreen(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
super.init();
|
||||||
|
AxisGridWidget agw = new AxisGridWidget(3, height - 22, width - 6, 20, AxisGridWidget.DisplayAxis.HORIZONTAL);
|
||||||
|
final TextFieldWidget searchField = new TextFieldWidget(textRenderer, this.width - 160, 20, Text.empty());
|
||||||
|
searchField.setPlaceholder(Text.translatable("widgets.ui.search"));
|
||||||
|
searchField.setChangedListener(this::search);
|
||||||
|
if (this.widgetList != null){
|
||||||
|
searchField.setText(this.getSearchQuery());
|
||||||
|
}
|
||||||
|
agw.add(searchField);
|
||||||
|
agw.add(new ButtonWidget.Builder(Text.translatable("widgets.ui.editPositions"), this::switchToEditPositions).build());
|
||||||
|
|
||||||
|
agw.refreshPositions();
|
||||||
|
agw.forEachChild(this::addDrawableChild);
|
||||||
|
|
||||||
|
if (Objects.equals(search, "")){
|
||||||
|
search("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSearchQuery() {
|
||||||
|
return search;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchQuery(String search) {
|
||||||
|
this.search = search;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void search(String query) {
|
||||||
|
this.setSearchQuery(query);
|
||||||
|
widgetList = new WidgetListWidget(0, 0, width-4, height-24, Text.translatable("widgets.ui.config"), client, WidgetManager.getAllWidgets().stream().filter(this::searchQueryMatches).toList(), textRenderer, this.onWidgetEdit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void switchToEditPositions(ButtonWidget widget) {
|
||||||
|
widget.active = false;
|
||||||
|
assert client != null;
|
||||||
|
client.setScreen(new EditWidgetPositionsScreen(this, this.onWidgetEdit));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
if (super.mouseClicked(mouseX, mouseY, button)){
|
||||||
|
return true;
|
||||||
|
} else return widgetList.mouseClicked(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
|
||||||
|
if (super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)){
|
||||||
|
return true;
|
||||||
|
} else return widgetList.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
assert client != null;
|
||||||
|
final double time = getScreenTimeMs();
|
||||||
|
if (time < 400){
|
||||||
|
context.getMatrices().push();
|
||||||
|
final float v = (float) WidgetUtils.computeEasing(time / 400d);
|
||||||
|
context.getMatrices().translate(width / 2d - (width * v / 2d), height / 2d - (height * v / 2d), 0);
|
||||||
|
context.getMatrices().scale(v, v, 1);
|
||||||
|
}
|
||||||
|
super.render(context, mouseX, mouseY, delta);
|
||||||
|
if (widgetList != null){
|
||||||
|
widgetList.render(context, mouseX, mouseY, delta);
|
||||||
|
}
|
||||||
|
if (time < 400){
|
||||||
|
context.getMatrices().pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean searchQueryMatches(ModWidget widget) {
|
||||||
|
return widget.getName().getString().contains(search) || widget.getDescription().getString().contains(search) || widget.getId().toString().contains(search);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changedSettings(ModWidget widget) {
|
||||||
|
if (!widgetsEdited.contains(widget)){
|
||||||
|
widgetsEdited.add(widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package de.shiewk.widgets.client.screen;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.ModWidget;
|
||||||
|
import de.shiewk.widgets.client.screen.components.WidgetSettingsEditWidget;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Util;
|
||||||
|
|
||||||
|
public class WidgetSettingsScreen extends AnimatedScreen {
|
||||||
|
private static final Text previewText = Text.translatable("widgets.ui.preview");
|
||||||
|
private final ModWidget widget;
|
||||||
|
private final Runnable onChange;
|
||||||
|
public WidgetSettingsScreen(Screen parent, ModWidget widget) {
|
||||||
|
super(Text.translatable("widgets.ui.widgetSettings", widget.getName()), parent, 500);
|
||||||
|
this.widget = widget;
|
||||||
|
onChange = () -> {
|
||||||
|
widget.onSettingsChanged(widget.getSettings());
|
||||||
|
if (parent instanceof WidgetConfigScreen widgetConfigScreen){
|
||||||
|
widgetConfigScreen.changedSettings(widget);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
super.init();
|
||||||
|
addDrawableChild(new WidgetSettingsEditWidget(0, 0, this.width / 2 - 8, this.height, textRenderer, widget, this.onChange));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderScreenContents(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
context.drawText(textRenderer, previewText, this.width * 3 / 4 - textRenderer.getWidth(previewText) / 2, this.height / 50, 0xffffffff, false);
|
||||||
|
widget.render(context, Util.getMeasuringTimeNano(), textRenderer, this.width * 3 / 4 - widget.width() / 2, this.height / 2 - widget.height() / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
assert client != null;
|
||||||
|
client.setScreen(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
if (!widget.getSettings().isEnabled()){
|
||||||
|
widget.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package de.shiewk.widgets.client.screen.components;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.ModWidget;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.Element;
|
||||||
|
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
|
||||||
|
import net.minecraft.client.gui.screen.narration.NarrationPart;
|
||||||
|
import net.minecraft.client.gui.widget.GridWidget;
|
||||||
|
import net.minecraft.client.gui.widget.ScrollableWidget;
|
||||||
|
import net.minecraft.client.gui.widget.SimplePositioningWidget;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class WidgetListWidget extends ScrollableWidget {
|
||||||
|
|
||||||
|
private final MinecraftClient client;
|
||||||
|
private final List<ModWidget> widgets;
|
||||||
|
private final List<WidgetWidget> elements = new ArrayList<>();
|
||||||
|
private final TextRenderer textRenderer;
|
||||||
|
private final Consumer<ModWidget> onEdit;
|
||||||
|
|
||||||
|
|
||||||
|
public WidgetListWidget(int x, int y, int width, int height, Text message, MinecraftClient client, List<ModWidget> widgets, TextRenderer textRenderer, Consumer<ModWidget> onEdit) {
|
||||||
|
super(x, y, width, height, message);
|
||||||
|
this.client = client;
|
||||||
|
this.widgets = widgets;
|
||||||
|
this.textRenderer = textRenderer;
|
||||||
|
this.onEdit = onEdit;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(){
|
||||||
|
GridWidget gw = new GridWidget();
|
||||||
|
gw.getMainPositioner().margin(4, 4, 4, 4);
|
||||||
|
final GridWidget.Adder adder = gw.createAdder(this.width / 208);
|
||||||
|
for (ModWidget widget : widgets) {
|
||||||
|
adder.add(new WidgetWidget(0, 0, 200, 100, client, widget, textRenderer, onEdit));
|
||||||
|
}
|
||||||
|
gw.refreshPositions();
|
||||||
|
SimplePositioningWidget.setPos(gw, 0, 0, this.width, this.getContentsHeight(), 0.5F, 0.5F);
|
||||||
|
gw.forEachChild(w -> this.addWidget((WidgetWidget) w));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addWidget(WidgetWidget drawableElement) {
|
||||||
|
this.elements.add(drawableElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getContentsHeight() {
|
||||||
|
final int rowSize = this.width / 208;
|
||||||
|
final int rows = widgets.size() % rowSize == 0 ? widgets.size() / rowSize : widgets.size() / rowSize + 1;
|
||||||
|
return 10 + (rows * 108);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double getDeltaYPerScroll() {
|
||||||
|
return 35;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void renderContents(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
for (WidgetWidget element : elements) {
|
||||||
|
element.render(context, mouseX, (int) (mouseY + getScrollY()), delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
mouseY += getScrollY();
|
||||||
|
for (Element element : elements) {
|
||||||
|
if (element.mouseClicked(mouseX, mouseY, 0)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendClickableNarrations(NarrationMessageBuilder builder) {
|
||||||
|
for (ModWidget widget : widgets) {
|
||||||
|
builder.put(NarrationPart.HINT, widget.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void drawBox(DrawContext context, int x, int y, int width, int height) {}
|
||||||
|
}
|
||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
package de.shiewk.widgets.client.screen.components;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.ModWidget;
|
||||||
|
import de.shiewk.widgets.WidgetSettingOption;
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
|
||||||
|
import net.minecraft.client.gui.widget.ScrollableWidget;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class WidgetSettingsEditWidget extends ScrollableWidget {
|
||||||
|
private static final int COLOR_FG = Color.WHITE.getRGB(), COLOR_BG = new Color(0, 0, 0, 60).getRGB();
|
||||||
|
private final TextRenderer textRenderer;
|
||||||
|
private final ModWidget widget;
|
||||||
|
private final Runnable onChange;
|
||||||
|
private WidgetSettingOption focus = null;
|
||||||
|
private int contentsHeight = 10;
|
||||||
|
public WidgetSettingsEditWidget(int x, int y, int width, int height, TextRenderer textRenderer, ModWidget widget, Runnable onChange) {
|
||||||
|
super(x, y, width, height, Text.empty());
|
||||||
|
this.textRenderer = textRenderer;
|
||||||
|
this.widget = widget;
|
||||||
|
this.onChange = onChange;
|
||||||
|
for (WidgetSettingOption customSetting : widget.getSettings().getCustomSettings()) {
|
||||||
|
customSetting.setFocused(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getContentsHeight() {
|
||||||
|
return this.contentsHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double getDeltaYPerScroll() {
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void renderContents(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
context.getMatrices().push();
|
||||||
|
context.getMatrices().scale(2, 2, 2);
|
||||||
|
context.drawText(textRenderer, widget.getName(), this.width / 4 - textRenderer.getWidth(widget.getName()) / 2, this.height / 100, COLOR_FG, true);
|
||||||
|
context.getMatrices().pop();
|
||||||
|
int y = textRenderer.fontHeight * 2 + this.height / 50 + 5;
|
||||||
|
for (WidgetSettingOption setting : widget.getSettings().getCustomSettings()) {
|
||||||
|
if (this.width - setting.getWidth() > textRenderer.getWidth(setting.getName()) + 20){
|
||||||
|
setting.setX(this.getX() + this.width - setting.getWidth() - 5);
|
||||||
|
setting.setY(y);
|
||||||
|
context.drawText(textRenderer, setting.getName(), getX() + 10, y + (setting.getHeight() / 2), COLOR_FG, true);
|
||||||
|
} else {
|
||||||
|
setting.setX(this.getX() + this.width / 2 - setting.getWidth() / 2);
|
||||||
|
setting.setY(y + 9 + 5);
|
||||||
|
context.drawText(textRenderer, setting.getName(), getX() + getWidth() / 2 - textRenderer.getWidth(setting.getName()) / 2, y, COLOR_FG, true);
|
||||||
|
y += 9 + 5;
|
||||||
|
}
|
||||||
|
setting.render(context, mouseX, (int) (mouseY + getScrollY()), delta);
|
||||||
|
y += setting.getHeight();
|
||||||
|
y += 5;
|
||||||
|
}
|
||||||
|
this.contentsHeight = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
mouseY += getScrollY();
|
||||||
|
for (WidgetSettingOption customSetting : widget.getSettings().getCustomSettings()) {
|
||||||
|
if (mouseX >= customSetting.getX() && mouseX <= customSetting.getX() + customSetting.getWidth()
|
||||||
|
&& mouseY >= customSetting.getY() && mouseY <= customSetting.getY() + customSetting.getHeight()){
|
||||||
|
focus = customSetting;
|
||||||
|
customSetting.setFocused(true);
|
||||||
|
if (customSetting.mouseClicked(mouseX, mouseY + getScrollY(), button)){
|
||||||
|
onChange.run();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.mouseClicked(mouseX, mouseY - getScrollY(), button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||||
|
for (WidgetSettingOption customSetting : widget.getSettings().getCustomSettings()) {
|
||||||
|
if (customSetting.mouseReleased(mouseX, mouseY + getScrollY(), button)){
|
||||||
|
onChange.run();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.mouseReleased(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean charTyped(char chr, int modifiers) {
|
||||||
|
if (this.focus != null){
|
||||||
|
if (this.focus.charTyped(chr, modifiers)){
|
||||||
|
onChange.run();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.charTyped(chr, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
if (this.focus != null){
|
||||||
|
if (this.focus.keyPressed(keyCode, scanCode, modifiers)){
|
||||||
|
onChange.run();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
|
||||||
|
if (this.focus != null){
|
||||||
|
if (this.focus.keyReleased(keyCode, scanCode, modifiers)){
|
||||||
|
onChange.run();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.keyReleased(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendClickableNarrations(NarrationMessageBuilder builder) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void drawBox(DrawContext context, int x, int y, int width, int height) {
|
||||||
|
context.fill(x, y, x+width, y+height, COLOR_BG);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package de.shiewk.widgets.client.screen.components;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.ModWidget;
|
||||||
|
import de.shiewk.widgets.WidgetUtils;
|
||||||
|
import de.shiewk.widgets.client.screen.WidgetSettingsScreen;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
|
||||||
|
import net.minecraft.client.gui.widget.ClickableWidget;
|
||||||
|
import net.minecraft.text.OrderedText;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Util;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class WidgetWidget extends ClickableWidget {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected static final int COLOR_BG = new Color(0, 0, 0, 80).getRGB(),
|
||||||
|
COLOR_BG_HOVER = new Color(40, 40, 40, 80).getRGB(),
|
||||||
|
COLOR_FG = Color.WHITE.getRGB(),
|
||||||
|
COLOR_DISABLED = new Color(200, 0, 0, 200).getRGB(),
|
||||||
|
COLOR_DISABLED_HOVER = new Color(255, 0, 0, 200).getRGB(),
|
||||||
|
COLOR_ENABLED = new Color(0, 200, 0, 200).getRGB(),
|
||||||
|
COLOR_ENABLED_HOVER = new Color(0, 255, 0, 200).getRGB();
|
||||||
|
|
||||||
|
private final MinecraftClient client;
|
||||||
|
private final ModWidget widget;
|
||||||
|
private final TextRenderer textRenderer;
|
||||||
|
private final Consumer<ModWidget> onEdit;
|
||||||
|
|
||||||
|
private long toggleTime = 0;
|
||||||
|
|
||||||
|
public WidgetWidget(int x, int y, int width, int height, MinecraftClient client, ModWidget widget, TextRenderer textRenderer, Consumer<ModWidget> onEdit) {
|
||||||
|
super(x, y, width, height, widget.getName());
|
||||||
|
this.client = client;
|
||||||
|
this.widget = widget;
|
||||||
|
this.textRenderer = textRenderer;
|
||||||
|
this.onEdit = onEdit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMouseOver(double mouseX, double mouseY) {
|
||||||
|
return this.active && this.visible && mouseX >= (double)this.getX() && mouseY >= (double)this.getY() && mouseX < (double)(this.getX() + this.width) && mouseY < (double)(this.getY() + this.height - 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
boolean hover = this.isMouseOver(mouseX, mouseY);
|
||||||
|
boolean widgetEnabled = widget.getSettings().isEnabled();
|
||||||
|
context.fill(this.getX(), this.getY(), this.getX() + this.getWidth(), this.getY() + this.getHeight(), hover ? COLOR_BG_HOVER : COLOR_BG);
|
||||||
|
context.getMatrices().push();
|
||||||
|
context.getMatrices().scale(2, 2, 1);
|
||||||
|
int titleSize = textRenderer.getWidth(widget.getName());
|
||||||
|
context.drawText(textRenderer, widget.getName(), getX() / 2 + getWidth() / 4 - titleSize / 2, getY() / 2 + 4, COLOR_FG, false);
|
||||||
|
context.getMatrices().pop();
|
||||||
|
int y = this.getY() + 12 + textRenderer.fontHeight * 2;
|
||||||
|
for (Iterator<OrderedText> it = textRenderer.wrapLines(widget.getDescription(), this.getWidth() - 10).iterator(); it.hasNext(); y += 9) {
|
||||||
|
OrderedText t = it.next();
|
||||||
|
context.drawText(textRenderer, t, getX() + 5 + ((getWidth() - 5) / 2) - (textRenderer.getWidth(t) / 2), y, COLOR_FG, false);
|
||||||
|
}
|
||||||
|
this.renderToggleButton(context, mouseX, mouseY, delta, widgetEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean clicked(double mouseX, double mouseY) {
|
||||||
|
if (isMouseOver(mouseX, mouseY)){
|
||||||
|
client.setScreen(new WidgetSettingsScreen(client.currentScreen, widget));
|
||||||
|
return true;
|
||||||
|
} else if (isMouseOverToggle(mouseX, mouseY)){
|
||||||
|
this.toggleWidget();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleWidget() {
|
||||||
|
widget.getSettings().toggleEnabled(widget);
|
||||||
|
toggleTime = Util.getMeasuringTimeNano();
|
||||||
|
onEdit.accept(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderToggleButton(DrawContext context, int mouseX, int mouseY, float delta, boolean widgetEnabled){
|
||||||
|
boolean hoverToggle = this.isMouseOverToggle(mouseX, mouseY);
|
||||||
|
final int toggleColor;
|
||||||
|
final int toggleColorInvert;
|
||||||
|
if (hoverToggle){
|
||||||
|
if (widgetEnabled){
|
||||||
|
toggleColor = COLOR_ENABLED_HOVER;
|
||||||
|
toggleColorInvert = COLOR_DISABLED_HOVER;
|
||||||
|
} else {
|
||||||
|
toggleColor = COLOR_DISABLED_HOVER;
|
||||||
|
toggleColorInvert = COLOR_ENABLED_HOVER;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (widgetEnabled){
|
||||||
|
toggleColor = COLOR_ENABLED;
|
||||||
|
toggleColorInvert = COLOR_DISABLED;
|
||||||
|
} else {
|
||||||
|
toggleColor = COLOR_DISABLED;
|
||||||
|
toggleColorInvert = COLOR_ENABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toggleTime > Util.getMeasuringTimeNano() - 250000000){
|
||||||
|
context.fill(this.getX(), this.getY() + this.getHeight() - 24, this.getX() + this.getWidth(), this.getY() + this.getHeight(), toggleColorInvert);
|
||||||
|
context.fill(this.getX(), this.getY() + this.getHeight() - 24, (int) (WidgetUtils.computeEasing((Util.getMeasuringTimeNano() - toggleTime) / 250000000d) * this.getWidth() + this.getX()), this.getY() + this.getHeight(), toggleColor);
|
||||||
|
} else {
|
||||||
|
context.fill(this.getX(), this.getY() + this.getHeight() - 24, this.getX() + this.getWidth(), this.getY() + this.getHeight(), toggleColor);
|
||||||
|
}
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, Text.translatable(widgetEnabled ? "widgets.ui.enabled" : "widgets.ui.disabled"), this.getX() + (this.getWidth() / 2), this.getY() + this.getHeight() - 16, COLOR_FG);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMouseOverToggle(double mouseX, double mouseY) {
|
||||||
|
return this.active && this.visible && mouseX >= this.getX() && mouseY >= (this.getY() + this.height - 24) && mouseX < (this.getX() + this.width) && mouseY < (this.getY() + this.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendClickableNarrations(NarrationMessageBuilder builder) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModWidget getWidget() {
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package de.shiewk.widgets.mixin;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.widgets.CPSWidget;
|
||||||
|
import net.minecraft.client.Mouse;
|
||||||
|
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.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(Mouse.class)
|
||||||
|
public class MixinMouse {
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/Mouse;leftButtonClicked:Z"), method = "onMouseButton")
|
||||||
|
public void onLeftClick(long window, int button, int action, int mods, CallbackInfo ci){
|
||||||
|
if (action == 1) CPSWidget.clickLeft();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/Mouse;middleButtonClicked:Z"), method = "onMouseButton")
|
||||||
|
public void onMiddleClick(long window, int button, int action, int mods, CallbackInfo ci){
|
||||||
|
if (action == 1) CPSWidget.clickMiddle();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/Mouse;rightButtonClicked:Z"), method = "onMouseButton")
|
||||||
|
public void onRightClick(long window, int button, int action, int mods, CallbackInfo ci){
|
||||||
|
if (action == 1) CPSWidget.clickRight();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package de.shiewk.widgets.widgets;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.WidgetSettings;
|
||||||
|
import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.profiler.MultiValueDebugSampleLogImpl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BandwidthWidget extends BasicTextWidget {
|
||||||
|
public BandwidthWidget(Identifier id) {
|
||||||
|
super(id, List.of(
|
||||||
|
new ToggleWidgetSetting("dynamic_color", Text.translatable("widgets.widgets.bandwidth.dynamicColor"), true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int t = 0;
|
||||||
|
private boolean dynamicColor = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
t++;
|
||||||
|
if (t >= 20){
|
||||||
|
t = 0;
|
||||||
|
final MultiValueDebugSampleLogImpl packetSizeLog = MinecraftClient.getInstance().getDebugHud().getPacketSizeLog();
|
||||||
|
final int logLength = packetSizeLog.getLength();
|
||||||
|
final int avgCompileLength = 60;
|
||||||
|
long size = 0;
|
||||||
|
for (int i = logLength-1; i > logLength-avgCompileLength; i--) {
|
||||||
|
if (i < 0) break;
|
||||||
|
size += packetSizeLog.get(i);
|
||||||
|
}
|
||||||
|
long avgBytesPerSecond = size / avgCompileLength * 20;
|
||||||
|
this.renderText = Text.of(formatByteSize(avgBytesPerSecond));
|
||||||
|
if (this.dynamicColor){
|
||||||
|
if (avgBytesPerSecond < 100000){
|
||||||
|
this.textColor = 0x00ff00;
|
||||||
|
} else if (avgBytesPerSecond < 750000) {
|
||||||
|
this.textColor = 0xffff00;
|
||||||
|
} else {
|
||||||
|
this.textColor = 0xff3030;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatByteSize(long bytes) {
|
||||||
|
if (bytes > 1000) {
|
||||||
|
double mb = bytes / 100 / 10d;
|
||||||
|
return mb + " KB/s";
|
||||||
|
} else {
|
||||||
|
return bytes + " B/s";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSettingsChanged(WidgetSettings settings) {
|
||||||
|
super.onSettingsChanged(settings);
|
||||||
|
this.dynamicColor = ((ToggleWidgetSetting) settings.optionById("dynamic_color")).getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getName() {
|
||||||
|
return Text.translatable("widgets.widgets.bandwidth");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getDescription() {
|
||||||
|
return Text.translatable("widgets.widgets.bandwidth.description");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package de.shiewk.widgets.widgets;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.ModWidget;
|
||||||
|
import de.shiewk.widgets.WidgetSettingOption;
|
||||||
|
import de.shiewk.widgets.WidgetSettings;
|
||||||
|
import de.shiewk.widgets.widgets.settings.RGBAColorWidgetSetting;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class BasicTextWidget extends ModWidget {
|
||||||
|
protected Text renderText = Text.empty();
|
||||||
|
|
||||||
|
private static ObjectArrayList<WidgetSettingOption> getCustomSettings(List<WidgetSettingOption> otherCustomOptions) {
|
||||||
|
final ObjectArrayList<WidgetSettingOption> list = new ObjectArrayList<>(otherCustomOptions);
|
||||||
|
list.add(new RGBAColorWidgetSetting("backgroundcolor", Text.translatable("widgets.widgets.basictext.background"), 0, 0, 0, 80));
|
||||||
|
list.add(new RGBAColorWidgetSetting("textcolor", Text.translatable("widgets.widgets.basictext.textcolor"), 255, 255, 255, 255));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
protected BasicTextWidget(Identifier id, List<WidgetSettingOption> otherCustomOptions) {
|
||||||
|
super(id, getCustomSettings(otherCustomOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final int
|
||||||
|
DEFAULT_WIDTH = 80,
|
||||||
|
DEFAULT_HEIGHT = 9 + 12,
|
||||||
|
DEFAULT_BACKGROUND_COLOR = new Color(0, 0, 0, 80).getRGB(),
|
||||||
|
DEFAULT_TEXT_COLOR = new Color(255, 255 ,255, 255).getRGB();
|
||||||
|
|
||||||
|
protected int backgroundColor = DEFAULT_BACKGROUND_COLOR, textColor = DEFAULT_TEXT_COLOR;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int width() {
|
||||||
|
return DEFAULT_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int height() {
|
||||||
|
return DEFAULT_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, long n, TextRenderer textRenderer, int posX, int posY) {
|
||||||
|
context.fill(posX, posY, posX + width(), posY + height(), this.backgroundColor);
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, renderText, posX + (width() / 2), posY + 6, this.textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSettingsChanged(WidgetSettings settings) {
|
||||||
|
this.backgroundColor = ((RGBAColorWidgetSetting) settings.optionById("backgroundcolor")).getColor();
|
||||||
|
this.textColor = ((RGBAColorWidgetSetting) settings.optionById("textcolor")).getColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package de.shiewk.widgets.widgets;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.WidgetSettings;
|
||||||
|
import de.shiewk.widgets.widgets.settings.EnumWidgetSetting;
|
||||||
|
import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CPSWidget extends BasicTextWidget {
|
||||||
|
|
||||||
|
public static class Click {
|
||||||
|
private int ticks = 0;
|
||||||
|
|
||||||
|
public int tick(){
|
||||||
|
return ticks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean countLeftClicks = true;
|
||||||
|
private static boolean countMiddleClicks = true;
|
||||||
|
private static boolean countRightClicks = true;
|
||||||
|
|
||||||
|
private static final ObjectArrayList<Click> leftClicks = new ObjectArrayList<>();
|
||||||
|
private static final ObjectArrayList<Click> middleClicks = new ObjectArrayList<>();
|
||||||
|
private static final ObjectArrayList<Click> rightClicks = new ObjectArrayList<>();
|
||||||
|
|
||||||
|
private Appearance appearance = Appearance.UNIFIED;
|
||||||
|
|
||||||
|
public enum Appearance {
|
||||||
|
SPLIT_PIPE("pipe"),
|
||||||
|
SPLIT_SLASH("slash"),
|
||||||
|
UNIFIED("unified");
|
||||||
|
|
||||||
|
public final String key;
|
||||||
|
|
||||||
|
Appearance(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPSWidget(Identifier id) {
|
||||||
|
super(id, List.of(
|
||||||
|
new EnumWidgetSetting<>("appearance", Text.translatable("widgets.widgets.cps.appearance"), Appearance.class, Appearance.UNIFIED, appearance -> Text.translatable("widgets.widgets.cps.appearance."+appearance.key)),
|
||||||
|
new ToggleWidgetSetting("left", Text.translatable("widgets.widgets.cps.left"), true),
|
||||||
|
new ToggleWidgetSetting("middle", Text.translatable("widgets.widgets.cps.middle"), false),
|
||||||
|
new ToggleWidgetSetting("right", Text.translatable("widgets.widgets.cps.right"), true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clickLeft() {
|
||||||
|
if (countLeftClicks){
|
||||||
|
leftClicks.add(new Click());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clickMiddle() {
|
||||||
|
if (countMiddleClicks){
|
||||||
|
middleClicks.add(new Click());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clickRight() {
|
||||||
|
if (countRightClicks){
|
||||||
|
rightClicks.add(new Click());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
int left = 0;
|
||||||
|
int right = 0;
|
||||||
|
int middle = 0;
|
||||||
|
if (countLeftClicks) {
|
||||||
|
leftClicks.removeIf(click -> click.tick() >= 20);
|
||||||
|
left = leftClicks.size();
|
||||||
|
}
|
||||||
|
if (countRightClicks) {
|
||||||
|
rightClicks.removeIf(click -> click.tick() >= 20);
|
||||||
|
right = rightClicks.size();
|
||||||
|
}
|
||||||
|
if (countMiddleClicks) {
|
||||||
|
middleClicks.removeIf(click -> click.tick() >= 20);
|
||||||
|
middle = middleClicks.size();
|
||||||
|
}
|
||||||
|
switch (appearance){
|
||||||
|
case UNIFIED -> renderText = Text.literal((left + right + middle) + " CPS");
|
||||||
|
case SPLIT_PIPE, SPLIT_SLASH -> {
|
||||||
|
final StringBuilder sb = getClickText(left, middle, right);
|
||||||
|
renderText = Text.literal(sb + " CPS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NotNull StringBuilder getClickText(int left, int middle, int right) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (countLeftClicks){
|
||||||
|
sb.append(left);
|
||||||
|
}
|
||||||
|
if (countMiddleClicks){
|
||||||
|
if (!sb.isEmpty()){
|
||||||
|
sb.append(appearance == Appearance.SPLIT_PIPE ? " | " : "/");
|
||||||
|
}
|
||||||
|
sb.append(middle);
|
||||||
|
}
|
||||||
|
if (countRightClicks){
|
||||||
|
if (!sb.isEmpty()){
|
||||||
|
sb.append(appearance == Appearance.SPLIT_PIPE ? " | " : "/");
|
||||||
|
}
|
||||||
|
sb.append(right);
|
||||||
|
}
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSettingsChanged(WidgetSettings settings) {
|
||||||
|
super.onSettingsChanged(settings);
|
||||||
|
countLeftClicks = ((ToggleWidgetSetting) settings.optionById("left")).getValue();
|
||||||
|
countMiddleClicks = ((ToggleWidgetSetting) settings.optionById("middle")).getValue();
|
||||||
|
countRightClicks = ((ToggleWidgetSetting) settings.optionById("right")).getValue();
|
||||||
|
appearance = (Appearance) ((EnumWidgetSetting<?>) settings.optionById("appearance")).getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getName() {
|
||||||
|
return Text.translatable("widgets.widgets.cps");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getDescription() {
|
||||||
|
return Text.translatable("widgets.widgets.cps.description");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package de.shiewk.widgets.widgets;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.WidgetSettings;
|
||||||
|
import de.shiewk.widgets.widgets.settings.EnumWidgetSetting;
|
||||||
|
import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ClockWidget extends BasicTextWidget {
|
||||||
|
|
||||||
|
private int width = DEFAULT_WIDTH;
|
||||||
|
|
||||||
|
public enum TimeOption {
|
||||||
|
NO_TIME("none"),
|
||||||
|
HOUR_24("24hour"),
|
||||||
|
AM_PM("am_pm");
|
||||||
|
|
||||||
|
public final String key;
|
||||||
|
|
||||||
|
TimeOption(String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DateOption {
|
||||||
|
NO_DATE(null),
|
||||||
|
FULL_MONTH_DAY("MMMM dd"),
|
||||||
|
DAY_FULL_MONTH("dd. MMMM"),
|
||||||
|
ABB_MONTH_DAY("MMM dd"),
|
||||||
|
DAY_ABB_MONTH("dd. MMM"),
|
||||||
|
MONTH_DAY("MM/dd"),
|
||||||
|
MONTH_DAY_2("dd.MM"),
|
||||||
|
FULL_MONTH_DAY_YEAR("MMMM dd, y"),
|
||||||
|
ABB_MONTH_DAY_YEAR("MMM dd, y"),
|
||||||
|
DAY_FULL_MONTH_YEAR("dd. MMMM y"),
|
||||||
|
DAY_ABB_MONTH_YEAR("dd. MMM y"),
|
||||||
|
MONTH_DAY_YEAR("MM/dd/y"),
|
||||||
|
MONTH_DAY_YEAR_2("dd.MM.y");
|
||||||
|
|
||||||
|
public final String format;
|
||||||
|
|
||||||
|
DateOption(String format) {
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Text getName(){
|
||||||
|
return this.format == null ? Text.translatable("widgets.widgets.clock.dateFormat.none") : Text.of(new SimpleDateFormat(format).format(Date.from(Instant.now())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum WeekOption {
|
||||||
|
NO_DAY_OF_WEEK(null),
|
||||||
|
ABBREVIATED("E"),
|
||||||
|
FULL("EEEE");
|
||||||
|
|
||||||
|
public final String format;
|
||||||
|
|
||||||
|
WeekOption(String format) {
|
||||||
|
this.format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Text getName(){
|
||||||
|
return this.format == null ? Text.translatable("widgets.widgets.clock.weekFormat.none") : Text.of(new SimpleDateFormat(format).format(Date.from(Instant.now())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ClockWidget(Identifier id) {
|
||||||
|
super(id, List.of(
|
||||||
|
new EnumWidgetSetting<>("hour_format",
|
||||||
|
Text.translatable("widgets.widgets.clock.hourFormat"),
|
||||||
|
TimeOption.class,
|
||||||
|
TimeOption.HOUR_24,
|
||||||
|
timeOption -> Text.translatable("widgets.widgets.clock.hourFormat."+timeOption.key)),
|
||||||
|
new ToggleWidgetSetting("show_seconds",
|
||||||
|
Text.translatable("widgets.widgets.clock.showSeconds"),
|
||||||
|
true),
|
||||||
|
new EnumWidgetSetting<>("date_format",
|
||||||
|
Text.translatable("widgets.widgets.clock.dateFormat"),
|
||||||
|
DateOption.class,
|
||||||
|
DateOption.NO_DATE,
|
||||||
|
DateOption::getName),
|
||||||
|
new EnumWidgetSetting<>("week_format",
|
||||||
|
Text.translatable("widgets.widgets.clock.weekFormat"),
|
||||||
|
WeekOption.class,
|
||||||
|
WeekOption.NO_DAY_OF_WEEK,
|
||||||
|
WeekOption::getName)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm:ss aa EEEE");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int width() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
renderText = Text.literal(dateFormat.format(Date.from(Instant.now())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSettingsChanged(WidgetSettings settings) {
|
||||||
|
super.onSettingsChanged(settings);
|
||||||
|
String datePattern = "HH:mm:ss";
|
||||||
|
TimeOption timeOption = (TimeOption) ((EnumWidgetSetting<?>) settings.optionById("hour_format")).getValue();
|
||||||
|
DateOption dateOption = (DateOption) ((EnumWidgetSetting<?>) settings.optionById("date_format")).getValue();
|
||||||
|
WeekOption weekOption = (WeekOption) ((EnumWidgetSetting<?>) settings.optionById("week_format")).getValue();
|
||||||
|
boolean showSeconds = ((ToggleWidgetSetting) settings.optionById("show_seconds")).getValue();
|
||||||
|
if (timeOption == TimeOption.HOUR_24){
|
||||||
|
datePattern = showSeconds ? "HH:mm:ss" : "HH:mm";
|
||||||
|
} else if (timeOption == TimeOption.AM_PM){
|
||||||
|
datePattern = showSeconds ? "hh:mm:ss aa" : "hh:mm aa";
|
||||||
|
} else if (timeOption == TimeOption.NO_TIME){
|
||||||
|
datePattern = "";
|
||||||
|
}
|
||||||
|
if (dateOption.format != null){
|
||||||
|
if (datePattern.isEmpty()) {
|
||||||
|
datePattern = dateOption.format + datePattern;
|
||||||
|
} else {
|
||||||
|
datePattern = dateOption.format + " " + datePattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (weekOption.format != null){
|
||||||
|
if (datePattern.isEmpty()){
|
||||||
|
datePattern = weekOption.format + datePattern;
|
||||||
|
} else {
|
||||||
|
datePattern = weekOption.format + ", " + datePattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dateFormat = new SimpleDateFormat(datePattern);
|
||||||
|
width = Math.max(DEFAULT_WIDTH, MinecraftClient.getInstance().textRenderer.getWidth(dateFormat.format(Date.from(Instant.now()))) + 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getName() {
|
||||||
|
return Text.translatable("widgets.widgets.clock");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getDescription() {
|
||||||
|
return Text.translatable("widgets.widgets.clock.description");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package de.shiewk.widgets.widgets;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.ModWidget;
|
||||||
|
import de.shiewk.widgets.WidgetSettings;
|
||||||
|
import de.shiewk.widgets.widgets.settings.RGBAColorWidgetSetting;
|
||||||
|
import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CoordinatesWidget extends ModWidget {
|
||||||
|
public CoordinatesWidget(Identifier id) {
|
||||||
|
super(id, List.of(
|
||||||
|
new ToggleWidgetSetting("x", Text.translatable("widgets.widgets.coordinates.showX"), true),
|
||||||
|
new ToggleWidgetSetting("y", Text.translatable("widgets.widgets.coordinates.showY"), true),
|
||||||
|
new ToggleWidgetSetting("z", Text.translatable("widgets.widgets.coordinates.showZ"), true),
|
||||||
|
new RGBAColorWidgetSetting("backgroundcolor", Text.translatable("widgets.widgets.basictext.background"), 0, 0, 0, 80),
|
||||||
|
new RGBAColorWidgetSetting("textcolor", Text.translatable("widgets.widgets.basictext.textcolor"), 255, 255, 255, 255)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String textX = "X", textY = "Y", textZ = "Z";
|
||||||
|
private int txc = 0, tyc = 0, tzc = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, long measuringTimeNano, TextRenderer textRenderer, int posX, int posY) {
|
||||||
|
context.fill(posX, posY, posX + width(), posY + height(), this.backgroundColor);
|
||||||
|
final int PADDING = CoordinatesWidget.PADDING;
|
||||||
|
int y = PADDING;
|
||||||
|
if (showX){
|
||||||
|
y++;
|
||||||
|
context.drawText(textRenderer, "X: ", posX + PADDING, posY + y, textColor, true);
|
||||||
|
context.drawText(textRenderer, textX, posX + txc, posY + y, textColor, true);
|
||||||
|
y += textRenderer.fontHeight + 1;
|
||||||
|
}
|
||||||
|
if (showY){
|
||||||
|
y++;
|
||||||
|
context.drawText(textRenderer, "Y: ", posX + PADDING, posY + y, textColor, true);
|
||||||
|
context.drawText(textRenderer, textY, posX + tyc, posY + y, textColor, true);
|
||||||
|
y += textRenderer.fontHeight + 1;
|
||||||
|
}
|
||||||
|
if (showZ){
|
||||||
|
y++;
|
||||||
|
context.drawText(textRenderer, "Z: ", posX + PADDING, posY + y, textColor, true);
|
||||||
|
context.drawText(textRenderer, textZ, posX + tzc, posY + y, textColor, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
|
||||||
|
txc = width() - textRenderer.getWidth(textX) - PADDING;
|
||||||
|
tyc = width() - textRenderer.getWidth(textY) - PADDING;
|
||||||
|
tzc = width() - textRenderer.getWidth(textZ) - PADDING;
|
||||||
|
|
||||||
|
final ClientPlayerEntity player = MinecraftClient.getInstance().player;
|
||||||
|
if (player == null){
|
||||||
|
textX = "?";
|
||||||
|
textY = "?";
|
||||||
|
textZ = "?";
|
||||||
|
} else {
|
||||||
|
textX = String.valueOf(player.getBlockX());
|
||||||
|
textY = String.valueOf(player.getBlockY());
|
||||||
|
textZ = String.valueOf(player.getBlockZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getName() {
|
||||||
|
return Text.translatable("widgets.widgets.coordinates");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getDescription() {
|
||||||
|
return Text.translatable("widgets.widgets.coordinates.description");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final int
|
||||||
|
WIDTH = 80,
|
||||||
|
PADDING = 6,
|
||||||
|
DEFAULT_BACKGROUND_COLOR = new Color(0, 0, 0, 80).getRGB(),
|
||||||
|
DEFAULT_TEXT_COLOR = new Color(255, 255 ,255, 255).getRGB();
|
||||||
|
|
||||||
|
protected int backgroundColor = DEFAULT_BACKGROUND_COLOR, textColor = DEFAULT_TEXT_COLOR;
|
||||||
|
protected boolean showX = true, showY = true, showZ = true;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSettingsChanged(WidgetSettings settings) {
|
||||||
|
this.backgroundColor = ((RGBAColorWidgetSetting) settings.optionById("backgroundcolor")).getColor();
|
||||||
|
this.textColor = ((RGBAColorWidgetSetting) settings.optionById("textcolor")).getColor();
|
||||||
|
this.showX = ((ToggleWidgetSetting) settings.optionById("x")).getValue();
|
||||||
|
this.showY = ((ToggleWidgetSetting) settings.optionById("y")).getValue();
|
||||||
|
this.showZ = ((ToggleWidgetSetting) settings.optionById("z")).getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int width() {
|
||||||
|
return WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int height() {
|
||||||
|
int height = 2 * PADDING;
|
||||||
|
if (showX) height += 11;
|
||||||
|
if (showY) height += 11;
|
||||||
|
if (showZ) height += 11;
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package de.shiewk.widgets.widgets;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FPSWidget extends BasicTextWidget {
|
||||||
|
public FPSWidget(Identifier id) {
|
||||||
|
super(id, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
this.renderText = Text.literal(MinecraftClient.getInstance().getCurrentFps() + " FPS");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getName() {
|
||||||
|
return Text.translatable("widgets.widgets.fps");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getDescription() {
|
||||||
|
return Text.translatable("widgets.widgets.fps.description");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package de.shiewk.widgets.widgets;
|
||||||
|
|
||||||
|
import de.shiewk.widgets.WidgetSettings;
|
||||||
|
import de.shiewk.widgets.widgets.settings.ToggleWidgetSetting;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.Util;
|
||||||
|
import net.minecraft.util.profiler.MultiValueDebugSampleLogImpl;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PingWidget extends BasicTextWidget {
|
||||||
|
|
||||||
|
long lastPingQuery = 0;
|
||||||
|
public PingWidget(Identifier id) {
|
||||||
|
super(id, List.of(
|
||||||
|
new ToggleWidgetSetting("dynamic_color", Text.translatable("widgets.widgets.ping.dynamicColor"), true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
private boolean dynamicColor = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
final ClientPlayNetworkHandler networkHandler = MinecraftClient.getInstance().getNetworkHandler();
|
||||||
|
if (networkHandler != null){
|
||||||
|
if (lastPingQuery < Util.getMeasuringTimeMs() - 5000){
|
||||||
|
networkHandler.pingMeasurer.ping();
|
||||||
|
lastPingQuery = Util.getMeasuringTimeMs();
|
||||||
|
}
|
||||||
|
final MultiValueDebugSampleLogImpl pingLog = networkHandler.pingMeasurer.log;
|
||||||
|
final int logLength = pingLog.getLength();
|
||||||
|
final int avgCompileLength = 3;
|
||||||
|
long ping = 0;
|
||||||
|
for (int i = logLength-1; i > logLength-avgCompileLength; i--) {
|
||||||
|
if (i < 0) break;
|
||||||
|
ping += pingLog.get(i);
|
||||||
|
}
|
||||||
|
long avgPing = ping / avgCompileLength;
|
||||||
|
this.renderText = Text.of(avgPing + " ms");
|
||||||
|
if (this.dynamicColor){
|
||||||
|
if (avgPing < 50){
|
||||||
|
this.textColor = 0x00ff00;
|
||||||
|
} else if (avgPing < 120) {
|
||||||
|
this.textColor = 0xffff00;
|
||||||
|
} else {
|
||||||
|
this.textColor = 0xff3030;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSettingsChanged(WidgetSettings settings) {
|
||||||
|
super.onSettingsChanged(settings);
|
||||||
|
this.dynamicColor = ((ToggleWidgetSetting) settings.optionById("dynamic_color")).getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getName() {
|
||||||
|
return Text.translatable("widgets.widgets.ping");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getDescription() {
|
||||||
|
return Text.translatable("widgets.widgets.ping.description");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package de.shiewk.widgets.widgets;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PlayerCountWidget extends BasicTextWidget{
|
||||||
|
public PlayerCountWidget(Identifier id) {
|
||||||
|
super(id, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
final ClientPlayNetworkHandler networkHandler = MinecraftClient.getInstance().getNetworkHandler();
|
||||||
|
String online = networkHandler == null ? "?" : String.valueOf(networkHandler.getPlayerUuids().size());
|
||||||
|
this.renderText = Text.literal(Text.translatable("widgets.widgets.playerCount.online", online).getString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getName() {
|
||||||
|
return Text.translatable("widgets.widgets.playerCount");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getDescription() {
|
||||||
|
return Text.translatable("widgets.widgets.playerCount.description");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package de.shiewk.widgets.widgets;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.network.ServerInfo;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ServerIPWidget extends BasicTextWidget {
|
||||||
|
public ServerIPWidget(Identifier id) {
|
||||||
|
super(id, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
private int t = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
final ServerInfo serverEntry = MinecraftClient.getInstance().getCurrentServerEntry();
|
||||||
|
if (serverEntry != null){
|
||||||
|
this.renderText = Text.of(serverEntry.address);
|
||||||
|
} else {
|
||||||
|
this.renderText = Text.translatable("menu.singleplayer");
|
||||||
|
}
|
||||||
|
t++;
|
||||||
|
if (t >= 20){
|
||||||
|
t = 0;
|
||||||
|
this.width = MinecraftClient.getInstance().textRenderer.getWidth(this.renderText) + 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int width() {
|
||||||
|
return Math.max(super.width(), this.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getName() {
|
||||||
|
return Text.translatable("widgets.widgets.serverIP");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Text getDescription() {
|
||||||
|
return Text.translatable("widgets.widgets.serverIP.description");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package de.shiewk.widgets.widgets.settings;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import de.shiewk.widgets.WidgetSettingOption;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class EnumWidgetSetting<T extends Enum<T>> extends WidgetSettingOption {
|
||||||
|
|
||||||
|
private final Class<T> enumClass;
|
||||||
|
private T value;
|
||||||
|
private final Function<T, Text> enumNameGetter;
|
||||||
|
private int height = 0;
|
||||||
|
private boolean mouseClick = false;
|
||||||
|
private boolean changed = false;
|
||||||
|
|
||||||
|
public EnumWidgetSetting(String id, Text name, Class<T> enumClass, T defaultValue, Function<T, Text> enumNameGetter) {
|
||||||
|
super(id, name);
|
||||||
|
this.enumClass = enumClass;
|
||||||
|
this.value = defaultValue;
|
||||||
|
this.enumNameGetter = enumNameGetter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getValue(){
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement saveState() {
|
||||||
|
return new JsonPrimitive(value.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadState(JsonElement state) {
|
||||||
|
if (state.isJsonPrimitive() && state.getAsJsonPrimitive().isString()){
|
||||||
|
final String name = state.getAsString();
|
||||||
|
for (T constant : enumClass.getEnumConstants()) {
|
||||||
|
if (constant.name().equals(name)){
|
||||||
|
this.value = constant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int COLOR_SELECTED = new Color(0, 0x5f, 0x68, 255).getRGB(),
|
||||||
|
COLOR_UNSELECTED = new Color(0, 0, 0, 50).getRGB(),
|
||||||
|
COLOR_UNSELECTED_HOVER = new Color(80, 80, 80, 50).getRGB(),
|
||||||
|
COLOR_TEXT = new Color(255, 255, 255, 255).getRGB();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
|
||||||
|
int y = 0;
|
||||||
|
int nx = 5;
|
||||||
|
final int bx = getX() + getWidth();
|
||||||
|
for (T constant : enumClass.getEnumConstants()) {
|
||||||
|
final Text name = enumNameGetter.apply(constant);
|
||||||
|
final int textRendererWidth = textRenderer.getWidth(name);
|
||||||
|
if (nx != 5 && nx + textRendererWidth + 20 > this.getWidth()){
|
||||||
|
y += 24;
|
||||||
|
nx = 5;
|
||||||
|
}
|
||||||
|
final boolean hover = mouseX <= bx - nx && mouseX >= bx - nx - 10 - textRendererWidth && mouseY <= y + 19 + getY() && mouseY >= y + getY();
|
||||||
|
context.fill(bx - 10 - textRendererWidth - nx, y + getY(), bx - nx, y + 19 + getY(), constant == value ? COLOR_SELECTED : hover ? COLOR_UNSELECTED_HOVER : COLOR_UNSELECTED);
|
||||||
|
context.drawText(textRenderer, name, bx - nx - 5 - textRendererWidth, y + 5 + getY(), COLOR_TEXT, true);
|
||||||
|
if (hover && mouseClick){
|
||||||
|
this.value = constant;
|
||||||
|
this.changed = true;
|
||||||
|
}
|
||||||
|
nx += textRendererWidth + 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseClick = false;
|
||||||
|
this.height = y + 34;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
mouseClick = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||||
|
mouseClick = false;
|
||||||
|
boolean changed = this.changed;
|
||||||
|
this.changed = false;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package de.shiewk.widgets.widgets.settings;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import de.shiewk.widgets.WidgetSettingOption;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.font.TextRenderer;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class RGBAColorWidgetSetting extends WidgetSettingOption {
|
||||||
|
public RGBAColorWidgetSetting(String id, Text name, int defaultR, int defaultG, int defaultB, int defaultAlpha) {
|
||||||
|
super(id, name);
|
||||||
|
this.r = defaultR;
|
||||||
|
this.g = defaultG;
|
||||||
|
this.b = defaultB;
|
||||||
|
this.a = defaultAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int r;
|
||||||
|
private int g;
|
||||||
|
private int b;
|
||||||
|
private int a;
|
||||||
|
private boolean mouseClicked = false;
|
||||||
|
private int sv = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement saveState() {
|
||||||
|
return new JsonPrimitive(getColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor(){
|
||||||
|
return new Color(r, g, b, a).getRGB();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadState(JsonElement state) {
|
||||||
|
if (state.isJsonPrimitive() && state.getAsJsonPrimitive().isNumber()){
|
||||||
|
final Color color = new Color(state.getAsJsonPrimitive().getAsInt(), true);
|
||||||
|
this.r = color.getRed();
|
||||||
|
this.g = color.getGreen();
|
||||||
|
this.b = color.getBlue();
|
||||||
|
this.a = color.getAlpha();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return 28 + 127 + 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return 95;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
|
||||||
|
int o = 0;
|
||||||
|
for (int i = 0; i <= 255; i+=2) {
|
||||||
|
context.drawVerticalLine(this.getX() + 5 + 7 + o, this.getY() + 5, this.getY() + 20, new Color(i, g, b, a).getRGB());
|
||||||
|
context.drawVerticalLine(this.getX() + 5 + 7 + o, this.getY() + 25, this.getY() + 40, new Color(r, i, b, a).getRGB());
|
||||||
|
context.drawVerticalLine(this.getX() + 5 + 7 + o, this.getY() + 45, this.getY() + 60, new Color(r, g, i, a).getRGB());
|
||||||
|
context.drawVerticalLine(this.getX() + 5 + 7 + o, this.getY() + 65, this.getY() + 80, new Color(r, g, b, i).getRGB());
|
||||||
|
o++;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.drawText(textRenderer, "R", this.getX() + 7 - textRenderer.getWidth("R"), this.getY() + 5 + 4, 0xffffff, true);
|
||||||
|
context.drawText(textRenderer, "G", this.getX() + 7 - textRenderer.getWidth("G"), this.getY() + 25 + 4, 0xffffff, true);
|
||||||
|
context.drawText(textRenderer, "B", this.getX() + 7 - textRenderer.getWidth("B"), this.getY() + 45 + 4, 0xffffff, true);
|
||||||
|
context.drawText(textRenderer, "A", this.getX() + 7 - textRenderer.getWidth("A"), this.getY() + 65 + 4, 0xffffff, true);
|
||||||
|
|
||||||
|
context.drawText(textRenderer, String.valueOf(r), this.getX() + this.getWidth() - 19, this.getY() + 5 + 4, 0xffffff, true);
|
||||||
|
context.drawText(textRenderer, String.valueOf(g), this.getX() + this.getWidth() - 19, this.getY() + 25 + 4, 0xffffff, true);
|
||||||
|
context.drawText(textRenderer, String.valueOf(b), this.getX() + this.getWidth() - 19, this.getY() + 45 + 4, 0xffffff, true);
|
||||||
|
context.drawText(textRenderer, String.valueOf(a), this.getX() + this.getWidth() - 19, this.getY() + 65 + 4, 0xffffff, true);
|
||||||
|
|
||||||
|
context.drawVerticalLine(this.getX() + 5 + 7 + r/2, this.getY() + 4, this.getY() + 21, 0xffffffff);
|
||||||
|
context.drawVerticalLine(this.getX() + 5 + 7 + g/2, this.getY() + 24, this.getY() + 41, 0xffffffff);
|
||||||
|
context.drawVerticalLine(this.getX() + 5 + 7 + b/2, this.getY() + 44, this.getY() + 61, 0xffffffff);
|
||||||
|
context.drawVerticalLine(this.getX() + 5 + 7 + a/2, this.getY() + 64, this.getY() + 81, 0xffffffff);
|
||||||
|
|
||||||
|
if (mouseClicked){
|
||||||
|
int col = MathHelper.clamp((mouseX - this.getX() - 5 - 7) * 2, 0, 255);
|
||||||
|
if (sv == 0){
|
||||||
|
if (mouseY > this.getY() + 5 && mouseY < this.getY() + 20){
|
||||||
|
sv = 1;
|
||||||
|
} else if (mouseY > this.getY() + 25 && mouseY < this.getY() + 40){
|
||||||
|
sv = 2;
|
||||||
|
} else if (mouseY > this.getY() + 45 && mouseY < this.getY() + 60){
|
||||||
|
sv = 3;
|
||||||
|
} else if (mouseY > this.getY() + 65 && mouseY < this.getY() + 80){
|
||||||
|
sv = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (sv){
|
||||||
|
case 1 -> r = col;
|
||||||
|
case 2 -> g = col;
|
||||||
|
case 3 -> b = col;
|
||||||
|
case 4 -> a = col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
this.mouseClicked = true;
|
||||||
|
sv = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||||
|
this.mouseClicked = false;
|
||||||
|
final boolean c = this.sv != 0;
|
||||||
|
this.sv = 0;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package de.shiewk.widgets.widgets.settings;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import de.shiewk.widgets.WidgetSettingOption;
|
||||||
|
import de.shiewk.widgets.WidgetUtils;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Util;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class ToggleWidgetSetting extends WidgetSettingOption {
|
||||||
|
|
||||||
|
private boolean value;
|
||||||
|
private long toggleTime = 0;
|
||||||
|
|
||||||
|
public ToggleWidgetSetting(String id, Text name, boolean defaultValue) {
|
||||||
|
super(id, name);
|
||||||
|
this.value = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getValue(){
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement saveState() {
|
||||||
|
return new JsonPrimitive(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadState(JsonElement state) {
|
||||||
|
if (state.isJsonPrimitive() && state.getAsJsonPrimitive().isBoolean()){
|
||||||
|
this.value = state.getAsBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final int COLOR_ENABLED = new Color(0, 255, 0, 255).getRGB(),
|
||||||
|
COLOR_ENABLED_THUMB = new Color(0, 175, 0, 255).getRGB(),
|
||||||
|
COLOR_DISABLED = new Color(255, 0, 0, 255).getRGB(),
|
||||||
|
COLOR_DISABLED_THUMB = new Color(255, 200, 200, 255).getRGB();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
int col = value ? COLOR_ENABLED : COLOR_DISABLED;
|
||||||
|
int thumb = value ? COLOR_ENABLED_THUMB : COLOR_DISABLED_THUMB;
|
||||||
|
int thumbLoc = (Util.getMeasuringTimeNano() - toggleTime) < 300000000f ?
|
||||||
|
(int) (getX() + MathHelper.lerp(WidgetUtils.computeEasing((Util.getMeasuringTimeNano() - toggleTime) / 300000000f),
|
||||||
|
value ? 2 : getWidth() - 4 - 12,
|
||||||
|
value ? getWidth() - 4 - 12 : 2))
|
||||||
|
: value ? getX() + getWidth() - 4 - 12 : getX() + 4;
|
||||||
|
context.fill(getX() + 2, getY() + 2, getX() + getWidth() - 2, getY() + getHeight() - 2, col);
|
||||||
|
context.fill(thumbLoc, getY() + 4, thumbLoc + 12, getY() + getHeight() - 4, thumb);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
toggle();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggle(){
|
||||||
|
this.value = !value;
|
||||||
|
this.toggleTime = Util.getMeasuringTimeNano();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() {
|
||||||
|
return 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"widgets.ui.config": "Widgets-Konfiguration",
|
||||||
|
"widgets.ui.editPositions": "Layout bearbeiten",
|
||||||
|
"widgets.widgets.fps": "FPS",
|
||||||
|
"widgets.widgets.fps.description": "Zeigt deine aktuellen FPS an.",
|
||||||
|
"widgets.ui.disabled": "Deaktiviert",
|
||||||
|
"widgets.ui.enabled": "Aktiviert",
|
||||||
|
"widgets.ui.search": "Suchen...",
|
||||||
|
"widgets.widgets.clock": "Uhr/Datum",
|
||||||
|
"widgets.widgets.clock.description": "Zeigt die aktuelle Uhrzeit und/oder das Datum an",
|
||||||
|
"widgets.ui.widgetSettings": "Bearbeite %s Einstellungen",
|
||||||
|
"widgets.widgets.basictext.background": "Hintergrundfarbe",
|
||||||
|
"widgets.widgets.basictext.textcolor": "Textfarbe",
|
||||||
|
"widgets.ui.preview": "Vorschau",
|
||||||
|
"widgets.widgets.clock.hourFormat": "Stundenformat",
|
||||||
|
"widgets.widgets.clock.hourFormat.none": "Keine Zeitangabe",
|
||||||
|
"widgets.widgets.clock.hourFormat.24hour": "24-Stunden-Zeit",
|
||||||
|
"widgets.widgets.clock.hourFormat.am_pm": "AM/PM",
|
||||||
|
"widgets.widgets.clock.dateFormat.none": "Kein Datum",
|
||||||
|
"widgets.widgets.clock.dateFormat": "Datumsformat",
|
||||||
|
"widgets.widgets.clock.weekFormat.none": "Nicht anzeigen",
|
||||||
|
"widgets.widgets.clock.weekFormat": "Wochentagformat",
|
||||||
|
"widgets.widgets.clock.showSeconds": "Sekunden anzeigen",
|
||||||
|
"widgets.widgets.coordinates": "Koordinaten",
|
||||||
|
"widgets.widgets.coordinates.description": "Zeigt deine aktuellen Koordinaten an",
|
||||||
|
"widgets.widgets.coordinates.showX": "X-Koordinate anzeigen:",
|
||||||
|
"widgets.widgets.coordinates.showY": "Y-Koordinate anzeigen:",
|
||||||
|
"widgets.widgets.coordinates.showZ": "Z-Koordinate anzeigen:",
|
||||||
|
"widgets.widgets.bandwidth": "Bandbreite",
|
||||||
|
"widgets.widgets.bandwidth.description": "Zeigt, wie viele Daten an den aktuell Server gesendet werden/vom Server an den Klient gesendet werden.",
|
||||||
|
"widgets.widgets.ping": "Ping",
|
||||||
|
"widgets.widgets.ping.description": "Zeigt deine Latenz zum Server an",
|
||||||
|
"widgets.widgets.bandwidth.dynamicColor": "Farbe dynamisch anzeigen",
|
||||||
|
"widgets.widgets.ping.dynamicColor": "Farbe dynamisch anzeigen",
|
||||||
|
"widgets.widgets.serverIP": "Server-IP",
|
||||||
|
"widgets.widgets.serverIP.description": "Zeigt die Serveradresse an",
|
||||||
|
"widgets.widgets.playerCount": "Spieleranzahl",
|
||||||
|
"widgets.widgets.playerCount.description": "Zeigt die Anzahl der online Spieler an. Dies könnte auf manchen Servern ungenau sein (besonders auf Servern, die gefälschte Spieler in der Tab-Liste anzeigen)",
|
||||||
|
"widgets.widgets.playerCount.online": "%s online",
|
||||||
|
"widgets.key.config": "Öffne Widget-Einstellungen",
|
||||||
|
"widgets.key.category": "Widgets",
|
||||||
|
"widgets.widgets.cps": "CPS",
|
||||||
|
"widgets.widgets.cps.description": "Zeigt deine Klicks pro Sekunde an",
|
||||||
|
"widgets.widgets.cps.left": "Zeigt/Zählt Links-Klicks",
|
||||||
|
"widgets.widgets.cps.middle": "Zeigt/Zählt Mittel-Klicks",
|
||||||
|
"widgets.widgets.cps.right": "Zeigt/Zählt Rechts-Klicks",
|
||||||
|
"widgets.widgets.cps.appearance": "Erscheinungsbild",
|
||||||
|
"widgets.widgets.cps.appearance.pipe": "Getrennt (Senkrechter Strich)",
|
||||||
|
"widgets.widgets.cps.appearance.slash": "Getrennt (Schrägstrich)",
|
||||||
|
"widgets.widgets.cps.appearance.unified": "Vereinheitlicht"
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"widgets.ui.config": "Widgets Config",
|
||||||
|
"widgets.ui.editPositions": "Edit Layout",
|
||||||
|
"widgets.widgets.fps": "FPS",
|
||||||
|
"widgets.widgets.fps.description": "Shows your current FPS.",
|
||||||
|
"widgets.ui.disabled": "Disabled",
|
||||||
|
"widgets.ui.enabled": "Enabled",
|
||||||
|
"widgets.ui.search": "Search...",
|
||||||
|
"widgets.widgets.clock": "Clock/Date",
|
||||||
|
"widgets.widgets.clock.description": "Shows the current time and/or date",
|
||||||
|
"widgets.ui.widgetSettings": "Edit %s settings",
|
||||||
|
"widgets.widgets.basictext.background": "Background color",
|
||||||
|
"widgets.widgets.basictext.textcolor": "Text color",
|
||||||
|
"widgets.ui.preview": "Preview",
|
||||||
|
"widgets.widgets.clock.hourFormat": "Hour Format",
|
||||||
|
"widgets.widgets.clock.hourFormat.none": "No time",
|
||||||
|
"widgets.widgets.clock.hourFormat.24hour": "Military Time",
|
||||||
|
"widgets.widgets.clock.hourFormat.am_pm": "AM/PM",
|
||||||
|
"widgets.widgets.clock.dateFormat.none": "No date",
|
||||||
|
"widgets.widgets.clock.dateFormat": "Date format",
|
||||||
|
"widgets.widgets.clock.weekFormat.none": "Don't show",
|
||||||
|
"widgets.widgets.clock.weekFormat": "Day of week format",
|
||||||
|
"widgets.widgets.clock.showSeconds": "Show seconds",
|
||||||
|
"widgets.widgets.coordinates": "Coordinates",
|
||||||
|
"widgets.widgets.coordinates.description": "Shows your current coordinates",
|
||||||
|
"widgets.widgets.coordinates.showX": "Show X coordinate:",
|
||||||
|
"widgets.widgets.coordinates.showY": "Show Y coordinate:",
|
||||||
|
"widgets.widgets.coordinates.showZ": "Show Z coordinate:",
|
||||||
|
"widgets.widgets.bandwidth": "Bandwidth",
|
||||||
|
"widgets.widgets.bandwidth.description": "Shows how much data is being read/sent from the server you're connected to.",
|
||||||
|
"widgets.widgets.ping": "Ping",
|
||||||
|
"widgets.widgets.ping.description": "Shows your latency to the server",
|
||||||
|
"widgets.widgets.bandwidth.dynamicColor": "Dynamic Color",
|
||||||
|
"widgets.widgets.ping.dynamicColor": "Dynamic Color",
|
||||||
|
"widgets.widgets.serverIP": "Server IP",
|
||||||
|
"widgets.widgets.serverIP.description": "Shows the server address",
|
||||||
|
"widgets.widgets.playerCount": "Player count",
|
||||||
|
"widgets.widgets.playerCount.description": "Shows the number of players online. May not be accurate on all servers (especially those that spawn fake players in the tab list)",
|
||||||
|
"widgets.widgets.playerCount.online": "%s online",
|
||||||
|
"widgets.key.config": "Open Widget Management",
|
||||||
|
"widgets.key.category": "Widgets",
|
||||||
|
"widgets.widgets.cps": "CPS",
|
||||||
|
"widgets.widgets.cps.description": "Shows your clicks per second",
|
||||||
|
"widgets.widgets.cps.left": "Display/Count left clicks",
|
||||||
|
"widgets.widgets.cps.middle": "Display/Count middle clicks",
|
||||||
|
"widgets.widgets.cps.right": "Display/Count right clicks",
|
||||||
|
"widgets.widgets.cps.appearance": "Appearance",
|
||||||
|
"widgets.widgets.cps.appearance.pipe": "Split (Pipe)",
|
||||||
|
"widgets.widgets.cps.appearance.slash": "Split (Slash)",
|
||||||
|
"widgets.widgets.cps.appearance.unified": "Unified"
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "widgets",
|
||||||
|
"version": "${version}",
|
||||||
|
"name": "Widgets",
|
||||||
|
"description": "Adds customizable in-game widgets to your game.",
|
||||||
|
"authors": [],
|
||||||
|
"contact": {
|
||||||
|
"sources": "https://github.com/Shiewk/widgets",
|
||||||
|
"issues": "https://github.com/Shiewk/widgets/issues"
|
||||||
|
},
|
||||||
|
"license": "LGPL-3.0-only",
|
||||||
|
"icon": "assets/widgets/icon.png",
|
||||||
|
"accessWidener": "widgets.accesswidener",
|
||||||
|
"environment": "client",
|
||||||
|
"entrypoints": {
|
||||||
|
"client": [
|
||||||
|
"de.shiewk.widgets.client.WidgetsModClient"
|
||||||
|
],
|
||||||
|
"main": [
|
||||||
|
"de.shiewk.widgets.WidgetsMod"
|
||||||
|
],
|
||||||
|
"modmenu": [
|
||||||
|
"de.shiewk.widgets.ModMenuConfig"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mixins": [
|
||||||
|
"widgets.mixins.json"
|
||||||
|
],
|
||||||
|
"depends": {
|
||||||
|
"fabricloader": ">=${loader_version}",
|
||||||
|
"fabric": "*",
|
||||||
|
"minecraft": "~${minecraft_version}"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
accessWidener v2 named
|
||||||
|
|
||||||
|
accessible field net/minecraft/client/network/ClientPlayNetworkHandler pingMeasurer Lnet/minecraft/client/network/PingMeasurer;
|
||||||
|
accessible field net/minecraft/client/network/PingMeasurer log Lnet/minecraft/util/profiler/MultiValueDebugSampleLogImpl;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"minVersion": "0.8",
|
||||||
|
"package": "de.shiewk.widgets.mixin",
|
||||||
|
"compatibilityLevel": "JAVA_21",
|
||||||
|
"mixins": [
|
||||||
|
],
|
||||||
|
"client": [
|
||||||
|
"MixinMouse"
|
||||||
|
],
|
||||||
|
"injectors": {
|
||||||
|
"defaultRequire": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user