Fixes notifications on non-screen elements adds logging for resps from api SPWORLDS Signed-off-by: Dmitrii <computer@yawaflua.tech> Took 2 hours 15 minutes
This commit is contained in:
committed by
Dmitrii
parent
3e9753055e
commit
d49ba6907e
@@ -50,6 +50,8 @@ dependencies {
|
||||
}
|
||||
|
||||
include(implementation("org.xerial:sqlite-jdbc:3.46.1.3"))
|
||||
include(clientImplementation("com.google.zxing:core:${project.zxing_version}"))
|
||||
include(clientImplementation("com.google.zxing:javase:${project.zxing_version}"))
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
||||
+2
-1
@@ -6,10 +6,11 @@ minecraft_version=1.21.11
|
||||
yarn_mappings=1.21.11+build.4
|
||||
loader_version=0.18.1
|
||||
# Mod Properties
|
||||
mod_version=0.1-pre-alpha
|
||||
mod_version=0.2-pre-alpha
|
||||
maven_group=git.yawaflua.tech
|
||||
archives_base_name=SPMega
|
||||
# Dependencies
|
||||
# check this on https://modmuss50.me/fabric.html
|
||||
fabric_version=0.141.1+1.21.11
|
||||
cloth_config_version=21.11.153
|
||||
zxing_version=3.5.3
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
package git.yawaflua.tech.spmega.client;
|
||||
|
||||
import git.yawaflua.tech.spmega.SPMega;
|
||||
import git.yawaflua.tech.spmega.client.qr.QRCodeScanner;
|
||||
import git.yawaflua.tech.spmega.client.ui.UiNotifications;
|
||||
import git.yawaflua.tech.spmega.client.ui.UiOpeners;
|
||||
import git.yawaflua.tech.spmega.client.ui.service.BankUiService;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
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.networking.v1.ClientPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
|
||||
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.fabricmc.fabric.api.event.player.UseEntityCallback;
|
||||
import net.minecraft.block.entity.SignBlockEntity;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.option.KeyBinding;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
import net.minecraft.entity.decoration.ItemFrameEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
@@ -22,6 +28,7 @@ import java.util.regex.Pattern;
|
||||
public class SPMegaClient implements ClientModInitializer {
|
||||
private static final Pattern ISOLATED_FIVE_DIGITS = Pattern.compile("(?<!\\d)(\\d{5})(?!\\d)");
|
||||
private static KeyBinding openBankMenuKeyBinding;
|
||||
private static KeyBinding scanQrKeyBinding;
|
||||
|
||||
private static String extractCardNumber(SignBlockEntity signBlockEntity) {
|
||||
String candidate = findFiveDigits(signBlockEntity.getFrontText().getMessages(false));
|
||||
@@ -31,16 +38,31 @@ public class SPMegaClient implements ClientModInitializer {
|
||||
return findFiveDigits(signBlockEntity.getBackText().getMessages(false));
|
||||
}
|
||||
|
||||
private static String extractCardNumber(ItemFrameEntity itemFrameEntity) {
|
||||
if (itemFrameEntity.getHeldItemStack().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return findFiveDigits(itemFrameEntity.getHeldItemStack().getName().getString());
|
||||
}
|
||||
|
||||
private static String findFiveDigits(Text[] lines) {
|
||||
for (Text line : lines) {
|
||||
Matcher matcher = ISOLATED_FIVE_DIGITS.matcher(line.getString());
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
String candidate = findFiveDigits(line.getString());
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String findFiveDigits(String text) {
|
||||
Matcher matcher = ISOLATED_FIVE_DIGITS.matcher(text);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
openBankMenuKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
@@ -50,12 +72,47 @@ public class SPMegaClient implements ClientModInitializer {
|
||||
KeyBinding.Category.GAMEPLAY
|
||||
));
|
||||
|
||||
scanQrKeyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
"key.spmega.scan_qr",
|
||||
InputUtil.Type.KEYSYM,
|
||||
GLFW.GLFW_KEY_O,
|
||||
KeyBinding.Category.GAMEPLAY
|
||||
));
|
||||
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
UiNotifications.instance().tick();
|
||||
while (openBankMenuKeyBinding.wasPressed()) {
|
||||
UiOpeners.openMainMenu(client);
|
||||
}
|
||||
while (scanQrKeyBinding.wasPressed()) {
|
||||
QRCodeScanner.ScanQrCode(client);
|
||||
}
|
||||
});
|
||||
|
||||
// World HUD path (when no screen is open).
|
||||
HudRenderCallback.EVENT.register((drawContext, tickDeltaManager) -> {
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
if (client.currentScreen != null || client.textRenderer == null) {
|
||||
return;
|
||||
}
|
||||
UiNotifications.instance().render(
|
||||
drawContext,
|
||||
client.textRenderer,
|
||||
client.getWindow().getScaledWidth(),
|
||||
client.getWindow().getScaledHeight()
|
||||
);
|
||||
});
|
||||
|
||||
// Screen path (for all GUI screens).
|
||||
ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) ->
|
||||
ScreenEvents.afterRender(screen).register((screenInstance, drawContext, mouseX, mouseY, tickDelta) -> {
|
||||
if (client.textRenderer == null) {
|
||||
return;
|
||||
}
|
||||
UiNotifications.instance().render(drawContext, client.textRenderer, scaledWidth, scaledHeight);
|
||||
})
|
||||
);
|
||||
|
||||
ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> {
|
||||
if (client.player != null) {
|
||||
BankUiService.instance().refreshOnServerJoin(client.player.getUuidAsString());
|
||||
@@ -73,17 +130,42 @@ public class SPMegaClient implements ClientModInitializer {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
if (!(world.getBlockEntity(hitResult.getBlockPos()) instanceof SignBlockEntity signBlockEntity)) {
|
||||
if (world.getBlockEntity(hitResult.getBlockPos()) instanceof SignBlockEntity signBlockEntity) {
|
||||
String cardNumber = extractCardNumber(signBlockEntity);
|
||||
if (cardNumber == null) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
UiOpeners.openPaymentMenu(MinecraftClient.getInstance(), cardNumber);
|
||||
return ActionResult.SUCCESS;
|
||||
} else {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
String cardNumber = extractCardNumber(signBlockEntity);
|
||||
if (cardNumber == null) {
|
||||
});
|
||||
|
||||
UseEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> {
|
||||
if (!world.isClient()) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
if (!player.isSneaking()) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
if (SPMega.getConfig() == null || !SPMega.getConfig().signQuickPayEnabled()) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
if (entity instanceof ItemFrameEntity itemFrameEntity) {
|
||||
String cardNumber = extractCardNumber(itemFrameEntity);
|
||||
if (cardNumber == null) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
UiOpeners.openPaymentMenu(MinecraftClient.getInstance(), cardNumber);
|
||||
return ActionResult.SUCCESS;
|
||||
} else {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
UiOpeners.openPaymentMenu(MinecraftClient.getInstance(), cardNumber);
|
||||
return ActionResult.SUCCESS;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package git.yawaflua.tech.spmega.client.qr;
|
||||
|
||||
import com.google.zxing.*;
|
||||
import com.google.zxing.common.GlobalHistogramBinarizer;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
import com.google.zxing.multi.GenericMultipleBarcodeReader;
|
||||
import git.yawaflua.tech.spmega.client.ui.QRcodeAcceptScreen;
|
||||
import git.yawaflua.tech.spmega.client.ui.UiNotifications;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.texture.NativeImage;
|
||||
import net.minecraft.client.util.ScreenshotRecorder;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class QRCodeScanner {
|
||||
|
||||
public static void ScanQrCode(MinecraftClient client) {
|
||||
if (client == null || client.player == null || client.getFramebuffer() == null) {
|
||||
return;
|
||||
}
|
||||
UiNotifications notifications = UiNotifications.instance();
|
||||
int framebufferWidth = client.getWindow().getFramebufferWidth();
|
||||
int framebufferHeight = client.getWindow().getFramebufferHeight();
|
||||
if (framebufferWidth <= 0 || framebufferHeight <= 0) {
|
||||
client.player.sendMessage(Text.translatable("message.spmega.qr.capture_failed"), false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ScreenshotRecorder.takeScreenshot(client.getFramebuffer(), nativeImage -> {
|
||||
try {
|
||||
if (nativeImage == null || nativeImage.getWidth() <= 0 || nativeImage.getHeight() <= 0) {
|
||||
client.execute(() -> {
|
||||
if (client.player != null) {
|
||||
notifications.show(Text.translatable("message.spmega.qr.capture_failed"));
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
String result = decodeQRCode(nativeImageToBufferedImage(nativeImage));
|
||||
client.execute(() -> {
|
||||
if (client.player == null) {
|
||||
return;
|
||||
}
|
||||
if (result == null) {
|
||||
notifications.show(Text.translatable("message.spmega.qr.not_found"));
|
||||
return;
|
||||
}
|
||||
|
||||
Text clickableLink = Text.literal(result)
|
||||
.styled(style -> style.withInsertion(result));
|
||||
client.player.sendMessage(Text.translatable("message.spmega.qr.found_link", clickableLink), false);
|
||||
client.setScreen(new QRcodeAcceptScreen(result, client.currentScreen));
|
||||
});
|
||||
} finally {
|
||||
if (nativeImage != null) {
|
||||
nativeImage.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
notifications.show(Text.translatable("message.spmega.qr.error"));
|
||||
}
|
||||
}
|
||||
|
||||
private static BufferedImage nativeImageToBufferedImage(NativeImage screenshot) {
|
||||
BufferedImage bufferedImage = new BufferedImage(
|
||||
screenshot.getWidth(),
|
||||
screenshot.getHeight(),
|
||||
BufferedImage.TYPE_INT_RGB
|
||||
);
|
||||
|
||||
for (int y = 0; y < screenshot.getHeight(); y++) {
|
||||
for (int x = 0; x < screenshot.getWidth(); x++) {
|
||||
int color = screenshot.getColorArgb(x, y);
|
||||
bufferedImage.setRGB(x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
return bufferedImage;
|
||||
}
|
||||
|
||||
private static String decodeQRCode(BufferedImage image) {
|
||||
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
|
||||
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
|
||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, Collections.singletonList(BarcodeFormat.QR_CODE));
|
||||
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
|
||||
hints.put(DecodeHintType.ALSO_INVERTED, Boolean.TRUE);
|
||||
|
||||
LuminanceSource source = new RGBLuminanceSource(image.getWidth(), image.getHeight(), image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth()));
|
||||
|
||||
String result = tryDecodeWithStrategies(source, hints);
|
||||
|
||||
if (result == null) {
|
||||
hints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
|
||||
result = tryDecodeWithStrategies(source, hints);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String tryDecodeWithStrategies(LuminanceSource source, Map<DecodeHintType, Object> hints) {
|
||||
try {
|
||||
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
||||
return new MultiFormatReader().decode(bitmap, hints).getText();
|
||||
} catch (NotFoundException e) {
|
||||
}
|
||||
|
||||
try {
|
||||
BinaryBitmap bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
|
||||
return new MultiFormatReader().decode(bitmap, hints).getText();
|
||||
} catch (NotFoundException e) {
|
||||
}
|
||||
try {
|
||||
GenericMultipleBarcodeReader reader = new GenericMultipleBarcodeReader(new MultiFormatReader());
|
||||
Result[] results = reader.decodeMultiple(new BinaryBitmap(new HybridBinarizer(source)), hints);
|
||||
if (results.length > 0) {
|
||||
return results[0].getText();
|
||||
}
|
||||
} catch (NotFoundException e) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,6 @@ public class AddCardScreen extends Screen {
|
||||
context.drawCenteredTextWithShadow(this.textRenderer, this.title, centerX, 24, 0xFFFFFF);
|
||||
context.drawTextWithShadow(this.textRenderer, Text.literal("Card ID (UUID):"), centerX - 140, startY - 10, 0xCCCCCC);
|
||||
context.drawTextWithShadow(this.textRenderer, Text.literal("Card Token:"), centerX - 140, startY + 18, 0xCCCCCC);
|
||||
notifications.render(context, this.textRenderer, this.width, this.height);
|
||||
}
|
||||
|
||||
private void submit() {
|
||||
|
||||
@@ -99,7 +99,6 @@ public class CardScreen extends Screen {
|
||||
context.drawCenteredTextWithShadow(this.textRenderer, this.title, centerX, 24, 0xFFFFFF);
|
||||
context.drawTextWithShadow(this.textRenderer, Text.literal("Список карт"), leftX, startY - 18, 0xBFBFBF);
|
||||
context.drawTextWithShadow(this.textRenderer, Text.literal("Действия"), rightX, startY - 18, 0xBFBFBF);
|
||||
notifications.render(context, this.textRenderer, this.width, this.height);
|
||||
}
|
||||
|
||||
private void updateCardButtonStates() {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package git.yawaflua.tech.spmega.client.ui;
|
||||
|
||||
import git.yawaflua.tech.spmega.client.qr.QRCodeScanner;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class MainBankScreen extends Screen {
|
||||
private final Screen parent;
|
||||
|
||||
@@ -34,6 +37,11 @@ public class MainBankScreen extends Screen {
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.literal("Закрыть"), button -> this.close())
|
||||
.dimensions(startX + (buttonWidth + gap) * 2, y, buttonWidth, 20)
|
||||
.build());
|
||||
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.translatable("button.spmega.scan_qr"), button -> {
|
||||
this.client.setScreen(null);
|
||||
QRCodeScanner.ScanQrCode(this.client);
|
||||
}).dimensions(centerX - 60, y + 28, 120, 20).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,7 +56,7 @@ public class MainBankScreen extends Screen {
|
||||
super.render(context, mouseX, mouseY, delta);
|
||||
|
||||
context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 24, 0xFFFFFF);
|
||||
context.drawCenteredTextWithShadow(this.textRenderer, Text.literal(greetingLine()), this.width / 2, 48, 0xFFD27F);
|
||||
context.drawCenteredTextWithShadow(this.textRenderer, Text.literal(greetingLine()), this.width / 2, 48, Color.WHITE.getRGB());
|
||||
}
|
||||
|
||||
private String greetingLine() {
|
||||
|
||||
@@ -189,7 +189,6 @@ public class PaymentScreen extends Screen {
|
||||
}
|
||||
|
||||
context.drawCenteredTextWithShadow(this.textRenderer, senderCardText, centerX, this.height - 20, 0xA9E5A9);
|
||||
notifications.render(context, this.textRenderer, this.width, this.height);
|
||||
}
|
||||
|
||||
private void submit() {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package git.yawaflua.tech.spmega.client.ui;
|
||||
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Util;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public class QRcodeAcceptScreen extends Screen {
|
||||
private final String url;
|
||||
private final Screen parent;
|
||||
|
||||
public QRcodeAcceptScreen(String url, Screen parent) {
|
||||
super(Text.translatable("screen.spmega.qr.confirm_title"));
|
||||
this.url = url;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.translatable("button.spmega.qr.cancel"), button -> {
|
||||
if (this.client != null) {
|
||||
this.client.setScreen(parent);
|
||||
}
|
||||
}).dimensions(this.width / 2 - 155, this.height / 2 + 30, 150, 20).build());
|
||||
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.translatable("button.spmega.qr.open_link"), button -> {
|
||||
try {
|
||||
Util.getOperatingSystem().open(new URI(url));
|
||||
} catch (Exception exception) {
|
||||
if (this.client != null && this.client.player != null) {
|
||||
this.client.player.sendMessage(Text.translatable("message.spmega.qr.failed_open"), false);
|
||||
}
|
||||
}
|
||||
if (this.client != null) {
|
||||
this.client.setScreen(parent);
|
||||
}
|
||||
}).dimensions(this.width / 2 + 5, this.height / 2 + 30, 150, 20).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (this.client != null) {
|
||||
this.client.setScreen(parent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
super.render(context, mouseX, mouseY, delta);
|
||||
|
||||
context.drawCenteredTextWithShadow(
|
||||
this.textRenderer,
|
||||
Text.translatable("screen.spmega.qr.accept_link"),
|
||||
this.width / 2,
|
||||
this.height / 2 - 30,
|
||||
0xFFFFFF
|
||||
);
|
||||
context.drawCenteredTextWithShadow(
|
||||
this.textRenderer,
|
||||
Text.literal(url),
|
||||
this.width / 2,
|
||||
this.height / 2 - 10,
|
||||
0xFFD27F
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ import net.minecraft.text.Text;
|
||||
import java.awt.*;
|
||||
|
||||
public final class UiNotifications {
|
||||
private static final long DEFAULT_DURATION_MS = 3500L;
|
||||
private static final int DEFAULT_DURATION_TICKS = 70;
|
||||
private static final UiNotifications INSTANCE = new UiNotifications();
|
||||
|
||||
private Text currentText = Text.empty();
|
||||
private long visibleUntilMs;
|
||||
private int remainingTicks;
|
||||
|
||||
private UiNotifications() {
|
||||
}
|
||||
@@ -31,7 +31,6 @@ public final class UiNotifications {
|
||||
}
|
||||
|
||||
try {
|
||||
System.out.println(raw);
|
||||
var reader = new JsonReader(new java.io.StringReader(raw));
|
||||
reader.setStrictness(Strictness.LENIENT);
|
||||
|
||||
@@ -42,7 +41,6 @@ public final class UiNotifications {
|
||||
}
|
||||
|
||||
} catch (Exception ignored) {
|
||||
System.out.println(ignored.getMessage());
|
||||
// fallback to raw text
|
||||
}
|
||||
|
||||
@@ -54,7 +52,7 @@ public final class UiNotifications {
|
||||
return;
|
||||
}
|
||||
currentText = text;
|
||||
visibleUntilMs = System.currentTimeMillis() + DEFAULT_DURATION_MS;
|
||||
remainingTicks = DEFAULT_DURATION_TICKS;
|
||||
}
|
||||
|
||||
public synchronized void showMessage(String message) {
|
||||
@@ -65,10 +63,7 @@ public final class UiNotifications {
|
||||
}
|
||||
|
||||
public synchronized void render(DrawContext context, TextRenderer textRenderer, int width, int height) {
|
||||
if (currentText == null || currentText.getString().isBlank()) {
|
||||
return;
|
||||
}
|
||||
if (System.currentTimeMillis() > visibleUntilMs) {
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,5 +78,20 @@ public final class UiNotifications {
|
||||
context.fill(x, y, x + boxWidth, y + boxHeight, Color.GRAY.getRGB());
|
||||
context.drawTextWithShadow(textRenderer, currentText, x + padding, y + padding, Color.WHITE.getRGB());
|
||||
}
|
||||
|
||||
public synchronized void tick() {
|
||||
if (remainingTicks <= 0) {
|
||||
return;
|
||||
}
|
||||
remainingTicks--;
|
||||
if (remainingTicks <= 0) {
|
||||
currentText = Text.empty();
|
||||
remainingTicks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean isVisible() {
|
||||
return currentText != null && !currentText.getString().isBlank() && remainingTicks > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
{
|
||||
"category.spmega": "SPMega",
|
||||
"key.spmega.open_menu": "Open SPMega Menu"
|
||||
"key.spmega.open_menu": "Open SPMega Menu",
|
||||
"key.spmega.scan_qr": "Scan QR from Screen",
|
||||
"button.spmega.scan_qr": "Scan QR",
|
||||
"button.spmega.qr.cancel": "Cancel",
|
||||
"button.spmega.qr.open_link": "Open Link",
|
||||
"screen.spmega.qr.confirm_title": "Link confirmation",
|
||||
"screen.spmega.qr.accept_link": "Open this link?",
|
||||
"message.spmega.qr.capture_failed": "Failed to capture Minecraft screen",
|
||||
"message.spmega.qr.not_found": "QR code not found on screen",
|
||||
"message.spmega.qr.invalid_url": "QR does not contain a valid http/https URL",
|
||||
"message.spmega.qr.opened": "Opened: %s",
|
||||
"message.spmega.qr.error": "Failed to scan QR from screen",
|
||||
"message.spmega.qr.hover_tip": "Click to open link",
|
||||
"message.spmega.qr.found_link": "Found link: %s",
|
||||
"message.spmega.qr.failed_open": "Failed to open link"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package git.yawaflua.tech.spmega;
|
||||
|
||||
public record ModConfig(String apiDomain, String apiToken, boolean signQuickPayEnabled) {
|
||||
public static final String DEFAULT_API_DOMAIN = "https://spworlds.ru";
|
||||
public static final String DEFAULT_API_DOMAIN = "https://spmega-api.yawaflua.tech";
|
||||
public static final String DEFAULT_API_TOKEN = "ulBKE9MWEtIGiPAhXV69I28W9BRiSrV3";
|
||||
public static final boolean DEFAULT_SIGN_QUICK_PAY_ENABLED = true;
|
||||
|
||||
|
||||
@@ -51,52 +51,72 @@ public final class SPWorldsApiClient {
|
||||
public CardInfo getCardInfo(CardAuth auth) throws IOException, InterruptedException {
|
||||
HttpRequest request = requestBuilder("/api/public/card", auth).GET().build();
|
||||
String body = send(request);
|
||||
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||
long balance = json.has("balance") ? json.get("balance").getAsLong() : 0L;
|
||||
String webhook = json.has("webhook") && !json.get("webhook").isJsonNull()
|
||||
? json.get("webhook").getAsString()
|
||||
: "";
|
||||
return new CardInfo(balance, webhook);
|
||||
try {
|
||||
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||
long balance = json.has("balance") ? json.get("balance").getAsLong() : 0L;
|
||||
String webhook = json.has("webhook") && !json.get("webhook").isJsonNull()
|
||||
? json.get("webhook").getAsString()
|
||||
: "";
|
||||
return new CardInfo(balance, webhook);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Failed to parse card info response: " + e.getMessage());
|
||||
System.out.println(body);
|
||||
|
||||
throw new IOException("Failed to parse card info response", e);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PlayerCard> getPlayerCards(String username, CardAuth auth) throws IOException, InterruptedException {
|
||||
HttpRequest request = requestBuilder("/api/public/accounts/" + username + "/cards", auth).GET().build();
|
||||
String body = send(request);
|
||||
JsonArray json = JsonParser.parseString(body).getAsJsonArray();
|
||||
try {
|
||||
JsonArray json = JsonParser.parseString(body).getAsJsonArray();
|
||||
|
||||
List<PlayerCard> cards = new ArrayList<>();
|
||||
for (JsonElement element : json) {
|
||||
JsonObject card = element.getAsJsonObject();
|
||||
String name = card.has("name") ? card.get("name").getAsString() : "";
|
||||
String number = card.has("number") ? card.get("number").getAsString() : "";
|
||||
cards.add(new PlayerCard(name, number));
|
||||
List<PlayerCard> cards = new ArrayList<>();
|
||||
for (JsonElement element : json) {
|
||||
JsonObject card = element.getAsJsonObject();
|
||||
String name = card.has("name") ? card.get("name").getAsString() : "";
|
||||
String number = card.has("number") ? card.get("number").getAsString() : "";
|
||||
cards.add(new PlayerCard(name, number));
|
||||
}
|
||||
return cards;
|
||||
} catch (Exception e) {
|
||||
System.out.println("Failed to parse player cards response: " + e.getMessage());
|
||||
System.out.println(body);
|
||||
throw new IOException("Failed to parse player cards response", e);
|
||||
}
|
||||
return cards;
|
||||
}
|
||||
|
||||
public AccountMe getAccountMe(CardAuth auth) throws IOException, InterruptedException {
|
||||
HttpRequest request = requestBuilder("/api/public/accounts/me", auth).GET().build();
|
||||
String body = send(request);
|
||||
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||
try {
|
||||
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||
|
||||
String id = json.has("id") ? json.get("id").getAsString() : "";
|
||||
String username = json.has("username") ? json.get("username").getAsString() : "";
|
||||
String minecraftUuid = json.has("minecraftUUID") ? json.get("minecraftUUID").getAsString() : "";
|
||||
String id = json.has("id") ? json.get("id").getAsString() : "";
|
||||
String username = json.has("username") ? json.get("username").getAsString() : "";
|
||||
String minecraftUuid = json.has("minecraftUUID") ? json.get("minecraftUUID").getAsString() : "";
|
||||
|
||||
List<AccountCard> cards = new ArrayList<>();
|
||||
if (json.has("cards") && json.get("cards").isJsonArray()) {
|
||||
for (JsonElement element : json.getAsJsonArray("cards")) {
|
||||
JsonObject card = element.getAsJsonObject();
|
||||
cards.add(new AccountCard(
|
||||
getString(card, "id"),
|
||||
getString(card, "name"),
|
||||
getString(card, "number"),
|
||||
card.has("color") && !card.get("color").isJsonNull() ? card.get("color").getAsInt() : 0
|
||||
));
|
||||
List<AccountCard> cards = new ArrayList<>();
|
||||
if (json.has("cards") && json.get("cards").isJsonArray()) {
|
||||
for (JsonElement element : json.getAsJsonArray("cards")) {
|
||||
JsonObject card = element.getAsJsonObject();
|
||||
cards.add(new AccountCard(
|
||||
getString(card, "id"),
|
||||
getString(card, "name"),
|
||||
getString(card, "number"),
|
||||
card.has("color") && !card.get("color").isJsonNull() ? card.get("color").getAsInt() : 0
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new AccountMe(id, username, minecraftUuid, cards);
|
||||
return new AccountMe(id, username, minecraftUuid, cards);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Failed to parse account info response: " + e.getMessage());
|
||||
System.out.println(body);
|
||||
|
||||
throw new IOException("Failed to parse account info response", e);
|
||||
}
|
||||
}
|
||||
|
||||
public TransactionResult createTransaction(CardAuth auth, String receiver, long amount, String comment)
|
||||
@@ -111,9 +131,17 @@ public final class SPWorldsApiClient {
|
||||
.build();
|
||||
|
||||
String body = send(request);
|
||||
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||
long balance = json.has("balance") ? json.get("balance").getAsLong() : 0L;
|
||||
return new TransactionResult(balance);
|
||||
try {
|
||||
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||
|
||||
long balance = json.has("balance") ? json.get("balance").getAsLong() : 0L;
|
||||
return new TransactionResult(balance);
|
||||
} catch (Exception exception) {
|
||||
System.out.println("Failed to parse transaction response: " + exception.getMessage());
|
||||
System.out.println(body);
|
||||
|
||||
throw new IOException("Failed to parse transaction response", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private HttpRequest.Builder requestBuilder(String path, CardAuth auth) {
|
||||
|
||||
Reference in New Issue
Block a user