Skip to content

Commit

Permalink
Add various operator utilities, bug fixes
Browse files Browse the repository at this point in the history
- Satellites can be listed and managed
- Operators can teleport to nearby radio stations
- Fixed comparator duration calculation for satellite stations
  • Loading branch information
FoundationGames committed Aug 2, 2023
1 parent 7d860d7 commit 4471518
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 2 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ loader_version=0.14.21
#Fabric api
fabric_version=0.84.0+1.20.1

mod_version = 1.0.0-beta.5
mod_version = 1.0.0-beta.6
maven_group = io.github.foundationgames
archives_base_name = phonos

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/io/github/foundationgames/phonos/Phonos.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import io.github.foundationgames.phonos.sound.emitter.SoundEmitterStorage;
import io.github.foundationgames.phonos.sound.stream.ServerOutgoingStreamHandler;
import io.github.foundationgames.phonos.util.PhonosUtil;
import io.github.foundationgames.phonos.world.command.PhonosCommands;
import io.github.foundationgames.phonos.world.sound.InputPlugPoint;
import io.github.foundationgames.phonos.world.sound.data.SoundDataTypes;
import net.fabricmc.api.ModInitializer;
Expand Down Expand Up @@ -110,6 +111,7 @@ public void onInitialize() {
});

RadioStorage.init();
PhonosCommands.init();
}

public static Identifier id(String path) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ protected int getComparatorOutput(int timer) {
return 0;
}

return MathHelper.clamp(Math.ceil(15 * timer / (float)this.playDuration), 0, 15);
return MathHelper.clamp((int) Math.ceil(15f * timer / this.playDuration), 0, 15);
}

public Vec3d launchpadPos() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ public static void save(Path folder) throws IOException {
doNotDelete.add(id);
}

Phonos.LOG.info("Saved all custom audio to <world>/phonos/");

try (var paths = Files.walk(folder, 1)) {
for (var path : paths.toList()) {
var filename = path.getFileName().toString();
Expand All @@ -147,6 +149,7 @@ public static void save(Path folder) throws IOException {
long id = Long.parseUnsignedLong(hexStr, 16);
if (!doNotDelete.contains(id)) {
Files.deleteIfExists(path);
Phonos.LOG.info("Deleted unused custom audio with ID {}", Long.toHexString(id));
}

} catch (NumberFormatException ignored) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.function.IntFunction;

public enum PhonosUtil {;
Expand Down Expand Up @@ -141,6 +143,26 @@ public static int readInt(InputStream stream) throws IOException {
return r;
}

public static String duration(int seconds) {
var fmt = NumberFormat.getInstance(Locale.ROOT);
fmt.setMinimumIntegerDigits(2);

if (seconds < 60) {
return "0:" + fmt.format(seconds);
}

int sec = seconds % 60;
int min = (seconds / 60) % 60;

if (seconds < 3600) {
return min + ":" + fmt.format(sec);
}

int hr = seconds / 3600;

return hr + ":" + fmt.format(min) + ":" + fmt.format(sec);
}

public static Path getCustomSoundFolder(MinecraftServer server) {
return server.getSavePath(WorldSavePath.ROOT).resolve("phonos");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public void remove(int channel, BlockPos pos) {
}
}

public LongSet getPoints(int channel) {
return channelToSources.get(channel);
}

public static RadarPoints get(ServerWorld world) {
return world.getPersistentStateManager().getOrCreate(RadarPoints::readNbt, RadarPoints::new, "phonos_radar_points");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package io.github.foundationgames.phonos.world.command;

import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import io.github.foundationgames.phonos.Phonos;
import io.github.foundationgames.phonos.block.entity.SatelliteStationBlockEntity;
import io.github.foundationgames.phonos.radio.RadioStorage;
import io.github.foundationgames.phonos.sound.custom.ServerCustomAudio;
import io.github.foundationgames.phonos.util.PhonosUtil;
import io.github.foundationgames.phonos.world.RadarPoints;
import net.fabricmc.fabric.api.command.v2.ArgumentTypeRegistry;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.argument.BlockPosArgumentType;
import net.minecraft.command.argument.PosArgument;
import net.minecraft.command.argument.serialize.ConstantArgumentSerializer;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.HoverEvent;
import net.minecraft.text.Text;
import net.minecraft.text.Texts;
import net.minecraft.util.Formatting;
import net.minecraft.util.math.BlockPos;

import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;

public class PhonosCommands {
public static void init() {
ArgumentTypeRegistry.registerArgumentType(Phonos.id("satellite"),
SatelliteArgumentType.class, ConstantArgumentSerializer.of(SatelliteArgumentType::new));

CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(literal("phonos")
.then(literal("radar")
.requires(src -> src.hasPermissionLevel(2))
.then(argument(
"channel",
IntegerArgumentType.integer(0, RadioStorage.CHANNEL_COUNT - 1))
.executes(ctx -> radar(
ctx.getSource(),
ctx.getArgument("channel", Integer.class)
))
)
)
.then(literal("satellite")
.then(literal("inspect").then(argument("pos", BlockPosArgumentType.blockPos())
.executes(ctx -> satelliteInspect(
ctx.getSource(),
ctx.getArgument("pos", PosArgument.class).toAbsoluteBlockPos(ctx.getSource())
))
)
)
.then(literal("list")
.requires(src -> src.hasPermissionLevel(2))
.executes(ctx -> satelliteList(
ctx.getSource()
))
)
.then(literal("crash")
.requires(src -> src.hasPermissionLevel(4) && src.getPlayer() != null)
.then(argument("id", new SatelliteArgumentType())
.executes(ctx -> satelliteCrash(
ctx.getSource(),
ctx.getArgument("id", Long.class)
))
)
)
)
);
});
}

public static int satelliteInspect(ServerCommandSource source, BlockPos pos) {
var world = source.getWorld();

if (world.getBlockEntity(pos) instanceof SatelliteStationBlockEntity be) {
long id = be.streamId;

if (!ServerCustomAudio.SAVED.containsKey(id)) {
source.sendError(Text.translatable("command.phonos.satellite.inspect.no_upload"));

return 1;
}

var aud = ServerCustomAudio.SAVED.get(id);
double sizeKB = (double)(aud.originalSize / 100) / 10D;
int duration = (int) Math.ceil((double) aud.originalSize / aud.sampleRate);
source.sendMessage(Text.translatable("command.phonos.satellite.entry",
Long.toHexString(id),
PhonosUtil.duration(duration),
sizeKB));

return 1;
}

source.sendError(Text.translatable("command.phonos.satellite.inspect.invalid"));
return 1;
}

public static int satelliteList(ServerCommandSource source) {
var set = ServerCustomAudio.SAVED.long2ObjectEntrySet();

if (set.isEmpty()) {
source.sendError(Text.translatable("command.phonos.satellite.list.none"));

return 1;
}

double totalSizeKB = 0;

for (var entry : set) {
double sizeKB = (double)(entry.getValue().originalSize / 100) / 10D;
int duration = (int) Math.ceil((double) entry.getValue().originalSize / entry.getValue().sampleRate);
source.sendMessage(Text.translatable("command.phonos.satellite.entry",
Long.toHexString(entry.getLongKey()),
PhonosUtil.duration(duration),
sizeKB));
totalSizeKB += entry.getValue().originalSize;
}

totalSizeKB = (double)((int)totalSizeKB / 100) / 10D;
source.sendMessage(Text.translatable("command.phonos.satellite.list.info", set.size(), totalSizeKB));

return 1;
}

public static int satelliteCrash(ServerCommandSource source, long id) throws CommandSyntaxException {
var idStr = Long.toHexString(id);
Phonos.LOG.info("Satellite {} was crashed via command by player {}.", idStr, source.getPlayerOrThrow());

ServerCustomAudio.deleteSaved(source.getServer(), id);
source.sendMessage(Text.translatable("command.phonos.satellite.crash", idStr));

return 1;
}

public static int radar(ServerCommandSource source, int channel) {
var world = source.getWorld();
var origin = source.getPosition();

var radar = RadarPoints.get(world);
var pos = new BlockPos.Mutable();

var result = new BlockPos.Mutable();
double minSqDist = Double.POSITIVE_INFINITY;

var points = radar.getPoints(channel);
if (points == null || points.size() == 0) {
source.sendError(Text.translatable("command.phonos.radar.none_found", channel));

return 1;
}

for (long l : radar.getPoints(channel)) {
pos.set(l);

double sqDist = origin.squaredDistanceTo(pos.getX(), pos.getY(), pos.getZ());
if (sqDist < minSqDist) {
result.set(pos);
minSqDist = sqDist;
}
}

sendCoordinates(source, "command.phonos.radar.success", result.up());

return 1;
}

private static void sendCoordinates(ServerCommandSource source, String key, BlockPos pos) {
Text coords = Texts.bracketed(
Text.translatable("chat.coordinates", pos.getX(), pos.getY(), pos.getZ())
).styled(style ->
style.withColor(Formatting.GREEN)
.withClickEvent(
new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/tp @s " + pos.getX() + " " + pos.getY() + " " + pos.getZ()))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.translatable("chat.coordinates.tooltip"))));

source.sendFeedback(() -> Text.translatable(key, coords), false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.github.foundationgames.phonos.world.command;

import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import io.github.foundationgames.phonos.sound.custom.ServerCustomAudio;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;

import java.util.concurrent.CompletableFuture;

public class SatelliteArgumentType implements ArgumentType<Long> {
public static final SimpleCommandExceptionType INVALID_ID_EXCEPTION = new SimpleCommandExceptionType(Text.translatable("argument.phonos.idList.invalid"));

public SatelliteArgumentType() {
}

@Override
public Long parse(StringReader reader) throws CommandSyntaxException {
try {
var str = reader.readString();
return Long.parseUnsignedLong(str, 16);
} catch (NumberFormatException ex) {
throw INVALID_ID_EXCEPTION.create();
}
}

@Override
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
var input = builder.getInput().substring(builder.getStart());

if (context.getSource() instanceof ServerCommandSource) {
var savedIds = ServerCustomAudio.SAVED.keySet();

if (input.isBlank()) {
savedIds.forEach(l -> builder.suggest(Long.toHexString(l)));

return builder.buildFuture();
}

builder.suggest(input);

for (long id : savedIds) {
var idStr = Long.toHexString(id);

if (idStr.startsWith(input)) {
builder.suggest(idStr);
}
}

return builder.buildFuture();
}

return Suggestions.empty();
}
}
11 changes: 11 additions & 0 deletions src/main/resources/assets/phonos/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@
"message.phonos.satellite_launching": "Launch in progress!",
"message.phonos.no_satellite": "Place a satellite on the launch pad first!",

"command.phonos.radar.none_found": "Found no radio emitters on channel %s.",
"command.phonos.radar.success": "Nearest radio emitter located at %s.",
"command.phonos.satellite.inspect.no_upload": "This station has no orbiting satellite!",
"command.phonos.satellite.inspect.invalid": "This block is not a satellite station!",
"command.phonos.satellite.crash": "Crashed satellite with id %s.",
"command.phonos.satellite.entry": "ID: %s, Duration: %s, Size: %s KB",
"command.phonos.satellite.list.info": "Found %s orbiting, total size %s KB",
"command.phonos.satellite.list.none": "No satellites in orbit.",

"argument.phonos.idList.invalid": "Invalid ID!",

"block.phonos.loudspeaker": "Loudspeaker",
"block.phonos.electronic_jukebox": "Electronic Jukebox",
"block.phonos.electronic_note_block": "Electronic Note Block",
Expand Down

0 comments on commit 4471518

Please sign in to comment.