Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ subprojects {
apply plugin: 'org.cadixdev.licenser'

ext {
baseVersion = '1.10.158'
baseVersion = '1.10.165'
pluginVersion = baseVersion + '-SNAPSHOT'
pluginDescription = 'spark is a performance profiling plugin/mod for Minecraft clients, servers and proxies.'

Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ rootProject.name = 'spark-extra-platforms'
include (
'spark-folia',
'spark-geyser',
'spark-hytale',
'spark-minestom',
'spark-nukkit',
'spark-sponge7',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public FoliaTickStatistics(Server server) {
this.regionSupplier = new WeakReferenceExpiringSupplier<>(() -> getRegions(server), 5, TimeUnit.MILLISECONDS);
}

@Override
public int gameTargetTps() {
return 20;
}

@Override
public double tps5Sec() {
return tps(StatisticWindow.TicksPerSecond.SECONDS_5);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void onShutdown(GeyserShutdownEvent ignored) {

@Subscribe
public void onCommandDefine(GeyserDefineCommandsEvent event) {
for (me.lucko.spark.common.command.Command command : this.platform.getCommands()) {
for (me.lucko.spark.common.command.Command command : this.platform.getCommandManager().getCommands()) {
event.register(Command.builder(this)
.source(CommandSource.class)
.name(command.primaryAlias())
Expand Down
56 changes: 56 additions & 0 deletions spark-hytale/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
plugins {
id 'com.gradleup.shadow' version '8.3.0'
}

tasks.withType(JavaCompile) {
options.release = 21
}

dependencies {
implementation "me.lucko:spark-common:${project.baseVersion}-SNAPSHOT"

implementation 'com.google.guava:guava:29.0-jre' // TODO: :(
implementation 'org.slf4j:slf4j-nop:1.7.36' // TODO: :(

compileOnly 'com.hypixel.hytale:Server:2026.01.24-6e2d4fc36'
}

repositories {
maven { url 'https://maven.hytale.com/release/' }
}

processResources {
from(sourceSets.main.resources.srcDirs) {
expand (
'pluginVersion': project.pluginVersion,
'pluginDescription': project.pluginDescription
)
include 'manifest.json'
}
}

shadowJar {
archiveFileName = "spark-${project.pluginVersion}-hytale.jar"

dependencies {
exclude(dependency('org.checkerframework:checker-qual'))
exclude(dependency('com.google.code.findbugs:jsr305'))
}

relocate 'net.kyori.adventure', 'me.lucko.spark.lib.adventure'
relocate 'net.kyori.examination', 'me.lucko.spark.lib.adventure.examination'
relocate 'net.kyori.option', 'me.lucko.spark.lib.adventure.option'
relocate 'net.bytebuddy', 'me.lucko.spark.lib.bytebuddy'
relocate 'com.google.protobuf', 'me.lucko.spark.lib.protobuf'
relocate 'org.objectweb.asm', 'me.lucko.spark.lib.asm'
relocate 'one.profiler', 'me.lucko.spark.lib.asyncprofiler'
relocate 'me.lucko.bytesocks.client', 'me.lucko.spark.lib.bytesocks'
relocate 'org.java_websocket', 'me.lucko.spark.lib.bytesocks.ws'

project.applyExcludes(delegate)
}

artifacts {
archives shadowJar
shadow shadowJar
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* This file is part of spark.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package me.lucko.spark.hytale;

import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.PluginClassLoader;
import me.lucko.spark.common.sampler.source.ClassSourceLookup;

import java.lang.reflect.Field;

public class HytaleClassSourceLookup extends ClassSourceLookup.ByClassLoader {
private static final Field PLUGIN_FIELD;

static {
try {
PLUGIN_FIELD = PluginClassLoader.class.getDeclaredField("plugin");
PLUGIN_FIELD.setAccessible(true);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}

@Override
public String identify(ClassLoader loader) throws ReflectiveOperationException {
if (loader instanceof PluginClassLoader pluginClassLoader) {
JavaPlugin plugin = (JavaPlugin) PLUGIN_FIELD.get(pluginClassLoader);
return plugin.getName();
}
return null;
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* This file is part of spark.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package me.lucko.spark.hytale;

import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.permissions.PermissionsModule;
import com.hypixel.hytale.server.core.receiver.IMessageReceiver;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import me.lucko.spark.common.command.sender.AbstractCommandSender;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;

import java.util.UUID;

public abstract class HytaleCommandSender<T extends IMessageReceiver> extends AbstractCommandSender<T> {

public static HytaleCommandSender<?> of(CommandSender commandSender) {
return new CommandSenderWrapper(commandSender);
}

public static HytaleCommandSender<?> of(PlayerRef playerRef) {
return new PlayerRefWrapper(playerRef);
}

protected HytaleCommandSender(T delegate) {
super(delegate);
}

@Override
protected Object getObjectForComparison() {
UUID uniqueId = getUniqueId();
if (uniqueId != null) {
return uniqueId;
}
return getName();
}

@Override
public void sendMessage(Component component) {
this.delegate.sendMessage(toHytaleMessage(component));
}

private static Message toHytaleMessage(Component component) {
if (!(component instanceof TextComponent text)) {
throw new UnsupportedOperationException("Unsupported component type: " + component.getClass());
}

Message message = Message.raw(text.content());

TextColor color = text.color();
if (color != null) {
message.color(color.asHexString());
}

TextDecoration.State bold = text.decoration(TextDecoration.BOLD);
if (bold != TextDecoration.State.NOT_SET) {
message.bold(bold == TextDecoration.State.TRUE);
}

TextDecoration.State italic = text.decoration(TextDecoration.ITALIC);
if (italic != TextDecoration.State.NOT_SET) {
message.italic(italic == TextDecoration.State.TRUE);
}

ClickEvent clickEvent = text.clickEvent();
if (clickEvent != null && clickEvent.action() == ClickEvent.Action.OPEN_URL) {
message.link(clickEvent.value());
}

message.insertAll(text.children().stream()
.map(HytaleCommandSender::toHytaleMessage)
.toList()
);
return message;
}

private static final class CommandSenderWrapper extends HytaleCommandSender<CommandSender> {
public CommandSenderWrapper(CommandSender delegate) {
super(delegate);
}

@Override
public String getName() {
return this.delegate.getDisplayName();
}

@Override
public UUID getUniqueId() {
if (this.delegate instanceof Player) {
return this.delegate.getUuid();
}
return null;
}

@Override
public boolean hasPermission(String permission) {
return this.delegate.hasPermission(permission);
}
}

private static final class PlayerRefWrapper extends HytaleCommandSender<PlayerRef> {
public PlayerRefWrapper(PlayerRef delegate) {
super(delegate);
}

@Override
public String getName() {
return this.delegate.getUsername();
}

@Override
public UUID getUniqueId() {
return this.delegate.getUuid();
}

@Override
public boolean hasPermission(String permission) {
return PermissionsModule.get().hasPermission(this.delegate.getUuid(), permission);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* This file is part of spark.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package me.lucko.spark.hytale;

import com.hypixel.hytale.common.util.java.ManifestUtil;
import me.lucko.spark.common.platform.PlatformInfo;

public class HytalePlatformInfo implements PlatformInfo {

@Override
public Type getType() {
return Type.SERVER;
}

@Override
public String getName() {
return "Hytale";
}

@Override
public String getBrand() {
return "Hytale";
}

@Override
public String getVersion() {
return ManifestUtil.getImplementationVersion();
}

@Override
public String getMinecraftVersion() {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* This file is part of spark.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package me.lucko.spark.hytale;

import com.google.common.collect.ImmutableMap;
import com.hypixel.hytale.protocol.packets.connection.PongType;
import com.hypixel.hytale.server.core.io.PacketHandler;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.Universe;
import me.lucko.spark.common.monitor.ping.PlayerPingProvider;

import java.util.Map;
import java.util.concurrent.TimeUnit;

public class HytalePlayerPingProvider implements PlayerPingProvider {

@Override
public Map<String, Integer> poll() {
ImmutableMap.Builder<String, Integer> builder = ImmutableMap.builder();
for (PlayerRef player : Universe.get().getPlayers()) {
PacketHandler.PingInfo pingInfo = player.getPacketHandler().getPingInfo(PongType.Tick);
long pingValue = pingInfo.getPingMetricSet().getLastValue();
int pingMillis = (int) TimeUnit.MILLISECONDS.convert(pingValue, PacketHandler.PingInfo.TIME_UNIT);
builder.put(player.getUsername(), pingMillis);
}
return builder.build();
}
}
Loading