generated from shrecknt/sun-addon-template
parent
3ab4c6667a
commit
8993d9c5a8
13 changed files with 186 additions and 109 deletions
10
README.md
10
README.md
|
@ -1,9 +1,5 @@
|
|||
# Sun Addon Template
|
||||
# Sun LiveOverflow Addon
|
||||
|
||||
## Setup
|
||||
Utilities for the LiveOverflow CTF server.
|
||||
|
||||
For setup instructions please see the [fabric wiki page](https://fabricmc.net/wiki/tutorial:setup) that relates to the IDE that you are using.
|
||||
|
||||
## License
|
||||
|
||||
This template is available under the CC0 license. Feel free to learn from it and incorporate it in your own projects.
|
||||
Only works with [Sun Client](https://git.shrecked.dev/Shrecknt/sun).
|
|
@ -10,8 +10,8 @@ loader_version=0.16.14
|
|||
|
||||
# Mod Properties
|
||||
mod_version=1.0.0
|
||||
maven_group=com.example
|
||||
archives_base_name=sun-addon-template
|
||||
maven_group=dev.shrecked.ctf
|
||||
archives_base_name=ctf
|
||||
|
||||
# Dependencies
|
||||
sun_version=1.2.1
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package com.example;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import dev.shrecked.sun.SunMod;
|
||||
import dev.shrecked.sun.components.SunAddonInitializer;
|
||||
import dev.shrecked.sun.components.command.CommandRegistry;
|
||||
import dev.shrecked.sun.components.module.ModuleRegistry;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
public class ExampleAddon implements SunAddonInitializer {
|
||||
public static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
SunMod.NORBIT.registerLambdaFactory("com.example", (lookupInMethod, klass) -> (MethodHandles.Lookup) lookupInMethod.invoke(null, klass, MethodHandles.lookup()));
|
||||
LOGGER.info("Sun example addon initialized!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadModules() {
|
||||
ModuleRegistry.reflectModulesFrom("com.example.modules");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCommands() {
|
||||
CommandRegistry.reflectCommandsFrom("com.example.commands");
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package com.example.commands;
|
||||
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import dev.shrecked.sun.components.annotation.SunCommand;
|
||||
import dev.shrecked.sun.components.command.Command;
|
||||
import dev.shrecked.sun.util.ChatUtil;
|
||||
import net.minecraft.command.CommandSource;
|
||||
|
||||
@SunCommand(name = "example-command", alias = {"ex"})
|
||||
public class ExampleCommand extends Command {
|
||||
@Override
|
||||
public void build(LiteralArgumentBuilder<CommandSource> builder) {
|
||||
builder.then(literal("echo")
|
||||
.then(argument("text", StringArgumentType.greedyString()).executes(context -> {
|
||||
String text = context.getArgument("text", String.class);
|
||||
ChatUtil.info(String.format("echo! %s", text));
|
||||
return SINGLE_SUCCESS;
|
||||
}))
|
||||
).build();
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package com.example.modules;
|
||||
|
||||
import com.example.ExampleAddon;
|
||||
import dev.shrecked.sun.components.annotation.SunModule;
|
||||
import dev.shrecked.sun.components.event.Events;
|
||||
import dev.shrecked.sun.components.module.Category;
|
||||
import dev.shrecked.sun.components.module.Module;
|
||||
import dev.shrecked.sun.components.setting.settings.StringSetting;
|
||||
import meteordevelopment.orbit.EventHandler;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@SunModule(key = "example-module", category = Category.World.class)
|
||||
public class ExampleModule extends Module {
|
||||
private final StringSetting text = config.add("text", new StringSetting("Example text display!"));
|
||||
|
||||
@Override
|
||||
protected void onEnable() {
|
||||
ExampleAddon.LOGGER.info("enabled example module!");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDisable() {
|
||||
ExampleAddon.LOGGER.info("disabled example module!");
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void onHudRender(Events.HudRender event) {
|
||||
event.context().drawText(
|
||||
MinecraftClient.getInstance().textRenderer,
|
||||
this.text.getValue(),
|
||||
5,
|
||||
5,
|
||||
Color.RED.getRGB(),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
40
src/main/java/dev/shrecked/ctf/CtfAddon.java
Normal file
40
src/main/java/dev/shrecked/ctf/CtfAddon.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package dev.shrecked.ctf;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import dev.shrecked.sun.SunMod;
|
||||
import dev.shrecked.sun.components.SunAddonInitializer;
|
||||
import dev.shrecked.sun.components.annotation.SunCategory;
|
||||
import dev.shrecked.sun.components.command.CommandRegistry;
|
||||
import dev.shrecked.sun.components.module.Category;
|
||||
import dev.shrecked.sun.components.module.ModuleRegistry;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
public class CtfAddon implements SunAddonInitializer {
|
||||
public static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
SunMod.NORBIT.registerLambdaFactory("dev.shrecked.ctf", (lookupInMethod, klass) -> (MethodHandles.Lookup) lookupInMethod.invoke(null, klass, MethodHandles.lookup()));
|
||||
LOGGER.info("Sun example addon initialized!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCategories() {
|
||||
Category.add(CtfCategory.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadModules() {
|
||||
ModuleRegistry.reflectModulesFrom("dev.shrecked.ctf.modules");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCommands() {
|
||||
CommandRegistry.reflectCommandsFrom("dev.shrecked.ctf.commands");
|
||||
}
|
||||
|
||||
@SunCategory(key = "ctf")
|
||||
public static class CtfCategory extends Category {}
|
||||
}
|
25
src/main/java/dev/shrecked/ctf/mixin/EventlessMoveMixin.java
Normal file
25
src/main/java/dev/shrecked/ctf/mixin/EventlessMoveMixin.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
package dev.shrecked.ctf.mixin;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import dev.shrecked.ctf.modules.RoboWalk;
|
||||
import dev.shrecked.sun.components.module.ModuleRegistry;
|
||||
import dev.shrecked.sun.modules.EventlessMove;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(EventlessMove.class)
|
||||
public class EventlessMoveMixin {
|
||||
/**
|
||||
* FIXME: The position generated by {@code from.lerp(to, 0.499)} ({@code ordinal = 1}) is rounded, so this movement is too far and generates a movement event.
|
||||
*/
|
||||
@WrapOperation(method = "onPlayerMove", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;)V", ordinal = 4))
|
||||
private void onPlayerMove(ClientPlayNetworkHandler instance, Packet<?> packet, Operation<Void> original) {
|
||||
RoboWalk roboWalk = ModuleRegistry.fromClass(RoboWalk.class);
|
||||
if (roboWalk.isEnabled()) roboWalk.forceDisableHandler = true;
|
||||
original.call(instance, packet);
|
||||
if (roboWalk.isEnabled()) roboWalk.forceDisableHandler = false;
|
||||
}
|
||||
}
|
41
src/main/java/dev/shrecked/ctf/modules/GameStateSpoofer.java
Normal file
41
src/main/java/dev/shrecked/ctf/modules/GameStateSpoofer.java
Normal file
|
@ -0,0 +1,41 @@
|
|||
package dev.shrecked.ctf.modules;
|
||||
|
||||
import dev.shrecked.ctf.CtfAddon;
|
||||
import dev.shrecked.sun.components.annotation.SunModule;
|
||||
import dev.shrecked.sun.components.event.Events;
|
||||
import dev.shrecked.sun.components.module.Module;
|
||||
import meteordevelopment.orbit.EventHandler;
|
||||
import net.minecraft.network.packet.s2c.play.GameStateChangeS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.WorldBorderInitializeS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.WorldBorderSizeChangedS2CPacket;
|
||||
import net.minecraft.world.border.WorldBorder;
|
||||
|
||||
@SunModule(key = "game-state-spoofer", category = CtfAddon.CtfCategory.class)
|
||||
public class GameStateSpoofer extends Module {
|
||||
@EventHandler
|
||||
private void onInboundPacket(Events.InboundPacket event) {
|
||||
if (event.packet instanceof WorldBorderSizeChangedS2CPacket) {
|
||||
event.packet = new WorldBorderSizeChangedS2CPacket(worldBorder());
|
||||
}
|
||||
|
||||
if (event.packet instanceof WorldBorderInitializeS2CPacket) {
|
||||
event.packet = new WorldBorderInitializeS2CPacket(worldBorder());
|
||||
}
|
||||
|
||||
if (event.packet instanceof GameStateChangeS2CPacket packet) {
|
||||
GameStateChangeS2CPacket.Reason reason = packet.getReason();
|
||||
if (reason == GameStateChangeS2CPacket.GAME_MODE_CHANGED
|
||||
|| reason == GameStateChangeS2CPacket.GAME_WON
|
||||
|| reason == GameStateChangeS2CPacket.DEMO_MESSAGE_SHOWN) {
|
||||
event.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static WorldBorder worldBorder() {
|
||||
WorldBorder worldBorder = new WorldBorder();
|
||||
worldBorder.setCenter(0, 0);
|
||||
worldBorder.setSize(Double.MAX_VALUE);
|
||||
return worldBorder;
|
||||
}
|
||||
}
|
54
src/main/java/dev/shrecked/ctf/modules/RoboWalk.java
Normal file
54
src/main/java/dev/shrecked/ctf/modules/RoboWalk.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
package dev.shrecked.ctf.modules;
|
||||
|
||||
import dev.shrecked.ctf.CtfAddon;
|
||||
import dev.shrecked.sun.components.annotation.SunModule;
|
||||
import dev.shrecked.sun.components.event.Events;
|
||||
import dev.shrecked.sun.components.module.Module;
|
||||
import dev.shrecked.sun.util.ChatUtil;
|
||||
import meteordevelopment.orbit.EventHandler;
|
||||
import meteordevelopment.orbit.EventPriority;
|
||||
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.play.VehicleMoveC2SPacket;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
@SunModule(key = "robo-walk", category = CtfAddon.CtfCategory.class)
|
||||
public class RoboWalk extends Module {
|
||||
public boolean forceDisableHandler = false;
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
private void onOutboundPacket(Events.OutboundPacket event) {
|
||||
if (forceDisableHandler) return;
|
||||
if (event.packet instanceof PlayerMoveC2SPacket packet && packet.changesPosition()) {
|
||||
double newX = round(packet.getX(0f));
|
||||
double newY = packet.getY(0f);
|
||||
double newZ = round(packet.getZ(0f));
|
||||
|
||||
PlayerMoveC2SPacket newPacket;
|
||||
if (packet instanceof PlayerMoveC2SPacket.PositionAndOnGround) {
|
||||
newPacket = new PlayerMoveC2SPacket.PositionAndOnGround(newX, newY, newZ, packet.isOnGround(), packet.horizontalCollision());
|
||||
} else if (packet instanceof PlayerMoveC2SPacket.Full) {
|
||||
newPacket = new PlayerMoveC2SPacket.Full(newX, newY, newZ, packet.getYaw(0f), packet.getPitch(0f), packet.isOnGround(), packet.horizontalCollision());
|
||||
} else {
|
||||
throw new RuntimeException("Unhandled movement packet type '" + packet.getClass().getSimpleName() + "'");
|
||||
}
|
||||
event.packet = newPacket;
|
||||
}
|
||||
|
||||
if (event.packet instanceof VehicleMoveC2SPacket(Vec3d position, float yaw, float pitch, boolean onGround)) {
|
||||
Vec3d fixedPosition = new Vec3d(
|
||||
round(position.getX()),
|
||||
position.getY(),
|
||||
round(position.getZ())
|
||||
);
|
||||
event.packet = new VehicleMoveC2SPacket(fixedPosition, yaw, pitch, onGround);
|
||||
}
|
||||
}
|
||||
|
||||
private static double round(double value) {
|
||||
double rounded = (double) (Math.round(value * 100)) / 100;
|
||||
double res = Math.nextAfter(rounded, rounded + Math.signum(value));
|
||||
long check = ((long) (res * 1000)) % 10;
|
||||
if (check != 0) ChatUtil.error("Bad round " + value);
|
||||
return res;
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 453 B After Width: | Height: | Size: 453 B |
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"sun.modules.example-module": "Example Module",
|
||||
"sun.modules.example-module.setting.text": "Example Text Config Option"
|
||||
"sun.category.ctf": "LiveOverflow CTF",
|
||||
"sun.modules.game-state-spoofer": "Game State Spoof",
|
||||
"sun.modules.robo-walk": "Robo-Walk"
|
||||
}
|
8
src/main/resources/ctf.mixins.json
Normal file
8
src/main/resources/ctf.mixins.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "dev.shrecked.ctf.mixin",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"client": [
|
||||
"EventlessMoveMixin"
|
||||
]
|
||||
}
|
|
@ -1,29 +1,32 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "sun-addon-template",
|
||||
"id": "ctf",
|
||||
"version": "${version}",
|
||||
"name": "Sun Addon Template",
|
||||
"description": "A template addon for Sun client",
|
||||
"name": "Sun LiveOverflow Addon",
|
||||
"description": "Sun client addon for the LiveOverflow CTF server",
|
||||
"authors": [
|
||||
"Me!"
|
||||
"Shrecknt"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "https://shrecked.dev/",
|
||||
"sources": "https://git.ssi.fyi/Shrecknt/sun-addon-template"
|
||||
},
|
||||
"license": "CC0-1.0",
|
||||
"icon": "assets/sun-addon-template/icon.png",
|
||||
"icon": "assets/ctf/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"sun-addon": [
|
||||
"com.example.ExampleAddon"
|
||||
"dev.shrecked.ctf.CtfAddon"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"ctf.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.15.0",
|
||||
"minecraft": ">=1.21.1",
|
||||
"java": ">=21",
|
||||
"fabric-api": "*",
|
||||
"sun": ">=1.1.0"
|
||||
"sun": ">=1.2.1"
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue