diff --git a/README.md b/README.md index 59a4ef3..ac0aecd 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,23 @@ +[//]: # (A skyblock mod with customizable islands, advanced island protection and support for expansion mods.) + +[//]: # () +[//]: # (NeoSkies provides it's own API and registries for other mods to add content and features and integrate with the island system.) + +[//]: # () +[//]: # (Each island have their own settings, those settings allow the owner to decide how other players can interact with the island, such as allowing interaction with doors, redstone, containers, etc.) + +[//]: # () +[//]: # (The mod uses the Common Economy API for currency, each island has it's account, that is shared between all island members.) + +[//]: # () +[//]: # (The mod is still in development and will change over time.) + +[//]: # () +[//]: # (This mod is a fork of Skylands, and the current island system and island templates are (mostly) from the original mod.) + +[//]: # () +[//]: # (Please provide feedback on the [discord server](https://discord.gg/MTqsjwMpN2), it helps a lot to continue developing the mod) + ## About diff --git a/build.gradle.kts b/build.gradle.kts index c627313..9e0f2f0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ import java.io.File import com.modrinth.minotaur.dependencies.ModDependency +//region Setup plugins { id("signing") id("maven-publish") @@ -8,15 +9,16 @@ plugins { id("com.modrinth.minotaur") version "2.+" } -val CHANGELOG: String = - if (file("CHANGELOG.md").exists()) { - file("CHANGELOG.md").readText() - } else { - "No changelog provided" - } +loom { + accessWidenerPath.set(file("src/main/resources/neoskies.accesswidener")) + splitEnvironmentSourceSets() -fun file(path: String): File { - return rootProject.file(path) + mods { + create("neoskies") { + sourceSet(sourceSets.main.get()) + sourceSet(sourceSets.getByName("client")) + } + } } sourceSets { @@ -30,37 +32,48 @@ sourceSets { compileClasspath += sourceSets.main.get().compileClasspath runtimeClasspath += sourceSets.main.get().runtimeClasspath } + + create("testmodClient") { + compileClasspath += main.get().compileClasspath + runtimeClasspath += main.get().runtimeClasspath + + compileClasspath += sourceSets.getByName("client").compileClasspath + runtimeClasspath += sourceSets.getByName("client").runtimeClasspath + + compileClasspath += sourceSets.getByName("testmod").compileClasspath + runtimeClasspath += sourceSets.getByName("testmod").runtimeClasspath + } } loom { - accessWidenerPath.set(file("src/main/resources/neoskies.accesswidener")) - runs { create("datagenServer") { server() - name = "Data Generation" + name("Data Generation") vmArg("-Dfabric-api.datagen") vmArg("-Dfabric-api.datagen.output-dir=${file("src/main/generated")}") vmArg("-Dfabric-api.datagen.modid=neoskies") - - //ideConfigGenerated = true - runDir = "build/datagen" + runDir("build/datagen") + ideConfigGenerated(true) } - create("testmodServer") { server() - name = "Testmod Server" + name("Testmod Server") + ideConfigGenerated(true) source(sourceSets.getByName("testmod")) } - create("testmodClient") { client() - name = "Testmod Client" + name("Testmod Client") runDir("run_client") - source(sourceSets.getByName("testmod")) + //TODO: Generate dev world + programArgs("--quickPlaySingleplayer \"world\"") + ideConfigGenerated(true) + source(sourceSets.getByName("testmodClient")) } } } +//endregion var archivesBaseName: String = property("archives_base_name").toString() base { @@ -76,6 +89,7 @@ repositories { maven("https://oss.sonatype.org/content/repositories/snapshots") maven("https://maven.ladysnake.org/releases") maven("https://maven.isxander.dev/releases") + maven("https://maven.deftu.dev/snapshots") maven("https://jitpack.io") maven { name = "Modrinth" @@ -122,11 +136,30 @@ dependencies { include(api("blue.endless:jankson:${property("jankson_version")}") as Any) //endregion + //region Client + "clientImplementation"("dev.deftu:dearimguimc-1.20.6-fabric:0.1.0") { + exclude(group = "net.fabricmc.fabric-api") + } + listOf( + "binding", + "lwjgl3", + "natives-windows", + "natives-linux", + "natives-macos" + ).forEach { module -> + val version = "1.86.11" + implementation("io.github.spair:imgui-java-$module:$version") { + exclude(group = "org.lwjgl") + } + } + //endregion + // region Tests "testmodImplementation"(sourceSets.main.get().output) //endregion } +//region Misc tasks.processResources { val map = mapOf( "version" to version @@ -156,7 +189,9 @@ tasks.jar { rename { "${it}_${property("archivesBaseName")}" } } } +//endregion +//region Publishing publishing { repositories { maven { @@ -181,6 +216,17 @@ signing { sign(publishing.publications["main"]) } +val CHANGELOG: String = + if (file("CHANGELOG.md").exists()) { + file("CHANGELOG.md").readText() + } else { + "No changelog provided" + } + +fun file(path: String): File { + return rootProject.file(path) +} + modrinth { val projectVersion: String = property("mod_version").toString() val projectVersionNumber: List = projectVersion.split(Regex("-"), 2) @@ -212,3 +258,4 @@ modrinth { ModDependency("placeholder-api", "embedded") ) } +//endregion diff --git a/gradle.properties b/gradle.properties index e251cd1..6cbdadf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,9 +9,9 @@ mod_version=1.0.0-alpha.1 # Dependencies | Check these on https://fabricmc.net/develop minecraft_version=1.20.6 yarn_mappings=1.20.6+build.1 -fabric_loader=0.15.10 +fabric_loader=0.15.11 -fabric_api=0.98.0+1.20.6 +fabric_api=0.100.4+1.20.6 cardinal_components_api=6.0.0-beta.3 diff --git a/src/client/java/com/awakenedredstone/neoskies/NeoSkiesClient.java b/src/client/java/com/awakenedredstone/neoskies/NeoSkiesClient.java new file mode 100644 index 0000000..3d038a2 --- /dev/null +++ b/src/client/java/com/awakenedredstone/neoskies/NeoSkiesClient.java @@ -0,0 +1,10 @@ +package com.awakenedredstone.neoskies; + +import net.fabricmc.api.ClientModInitializer; + +public class NeoSkiesClient implements ClientModInitializer { + @Override + public void onInitializeClient() { + + } +} diff --git a/src/client/resources/neoskies.client.mixins.json b/src/client/resources/neoskies.client.mixins.json new file mode 100644 index 0000000..4de9c26 --- /dev/null +++ b/src/client/resources/neoskies.client.mixins.json @@ -0,0 +1,10 @@ +{ + "required": true, + "package": "com.awakenedredstone.neoskies.mixin.client", + "compatibilityLevel": "JAVA_17", + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/src/main/java/com/awakenedredstone/neoskies/command/NeoSkiesCommands.java b/src/main/java/com/awakenedredstone/neoskies/command/NeoSkiesCommands.java index 83a1354..fa6c7e3 100644 --- a/src/main/java/com/awakenedredstone/neoskies/command/NeoSkiesCommands.java +++ b/src/main/java/com/awakenedredstone/neoskies/command/NeoSkiesCommands.java @@ -127,7 +127,6 @@ private static void registerAdminCommands(CommandDispatcher .putAny("current", integer) .build())); }, (timeTaken, scannedBlocks) -> { - Map.Entry i = scannedBlocks.entrySet().stream().findFirst().get(); source.sendMessage(Texts.of("Scanned %total% blocks in %time%", new MapBuilder.StringMap() .putAny("total", UnitConvertions.readableNumber(scannedBlocks.values().stream().mapToInt(value -> value).sum())) .putAny("time", UnitConvertions.formatTimings(timeTaken)) @@ -140,6 +139,7 @@ private static void registerAdminCommands(CommandDispatcher }) ) ).then(CommandManager.literal("list") + .requires(Permissions.require("neoskies.admin.island.list", 4)) .executes(context -> { LinedStringBuilder builder = new LinedStringBuilder(); List islands = IslandLogic.getInstance().islands.stuck; diff --git a/src/main/java/com/awakenedredstone/neoskies/command/admin/IslandDataCommand.java b/src/main/java/com/awakenedredstone/neoskies/command/admin/IslandDataCommand.java index 170869d..eeb6fef 100644 --- a/src/main/java/com/awakenedredstone/neoskies/command/admin/IslandDataCommand.java +++ b/src/main/java/com/awakenedredstone/neoskies/command/admin/IslandDataCommand.java @@ -24,36 +24,38 @@ public class IslandDataCommand { public static void init(CommandDispatcher dispatcher) { registerAdmin(dispatcher, adminNode() - .then(literal("island-data") - .then(literal("find") - .requires(Permissions.require("neoskies.admin.island.data.find", 4)) - .then(argument("player", StringArgumentType.word()) - .suggests((context, builder) -> { - List islands = IslandLogic.getInstance().islands.stuck; - for (Island island : islands) { - builder.suggest(island.owner.name); - island.members.forEach(member -> { - builder.suggest(member.name); - }); - } - return builder.buildFuture(); - }).executes(context -> { - String playerName = StringArgumentType.getString(context, "player"); - Optional islandOptional = NeoSkiesAPI.getIslandByPlayer(playerName); - return getIslandData(context.getSource(), islandOptional.orElse(null)); - }) - ) - ).then(literal("get") - .then(argument("id", StringArgumentType.word()) - .suggests(CommandUtils.ISLAND_SUGGESTIONS) - .executes(context -> { - String islandId = StringArgumentType.getString(context, "id"); - Optional islandOptional = NeoSkiesAPI.getIsland(UUID.fromString(islandId)); - return getIslandData(context.getSource(), islandOptional.orElse(null)); - }) - ) - ) + .then(literal("island-data") + .requires(Permissions.require("neoskies.admin.island.data", 4)) + .then(literal("find") + .requires(Permissions.require("neoskies.admin.island.data.find", 4)) + .then(argument("player", StringArgumentType.word()) + .suggests((context, builder) -> { + List islands = IslandLogic.getInstance().islands.stuck; + for (Island island : islands) { + builder.suggest(island.owner.name); + island.members.forEach(member -> { + builder.suggest(member.name); + }); + } + return builder.buildFuture(); + }).executes(context -> { + String playerName = StringArgumentType.getString(context, "player"); + Optional islandOptional = NeoSkiesAPI.getIslandByPlayer(playerName); + return getIslandData(context.getSource(), islandOptional.orElse(null)); + }) + ) + ).then(literal("get") + .requires(Permissions.require("neoskies.admin.island.data.get", 4)) + .then(argument("id", StringArgumentType.word()) + .suggests(CommandUtils.ISLAND_SUGGESTIONS) + .executes(context -> { + String islandId = StringArgumentType.getString(context, "id"); + Optional islandOptional = NeoSkiesAPI.getIsland(UUID.fromString(islandId)); + return getIslandData(context.getSource(), islandOptional.orElse(null)); + }) + ) ) + ) ); } @@ -73,17 +75,17 @@ private static int getIslandData(ServerCommandSource source, @Nullable Island is } MapBuilder.StringMap map = new MapBuilder.StringMap() - .put("id", island.getIslandId().toString()) - .put("owner", island.owner.name) - .put("members", members.toString()) - .putAny("balance", island.getWallet().balance()) - .putAny("has_nether", island.hasNether) - .putAny("has_end", island.hasEnd) - .putAny("spawn_pos", island.spawnPos) - .putAny("visit_pos", island.visitsPos) - .putAny("radius", island.radius) - .putAny("locked", island.locked) - .putAny("created", island.getCreated().toEpochMilli()); + .put("id", island.getIslandId().toString()) + .put("owner", island.owner.name) + .put("members", members.toString()) + .putAny("balance", island.getWallet().balance()) + .putAny("has_nether", island.hasNether) + .putAny("has_end", island.hasEnd) + .putAny("spawn_pos", island.spawnPos) + .putAny("visit_pos", island.visitsPos) + .putAny("radius", island.radius) + .putAny("locked", island.locked) + .putAny("created", island.getCreated().toEpochMilli()); source.sendFeedback(() -> Texts.of("message.neoskies.island_data", map.build()), false); return 1; } diff --git a/src/main/java/com/awakenedredstone/neoskies/command/island/HomeCommand.java b/src/main/java/com/awakenedredstone/neoskies/command/island/HomeCommand.java index 034dc58..5a80f37 100644 --- a/src/main/java/com/awakenedredstone/neoskies/command/island/HomeCommand.java +++ b/src/main/java/com/awakenedredstone/neoskies/command/island/HomeCommand.java @@ -1,6 +1,5 @@ package com.awakenedredstone.neoskies.command.island; -import com.awakenedredstone.neoskies.NeoSkies; import com.awakenedredstone.neoskies.api.NeoSkiesAPI; import com.awakenedredstone.neoskies.logic.Island; import com.awakenedredstone.neoskies.logic.IslandLogic; @@ -42,21 +41,4 @@ static void run(ServerPlayerEntity player) { } }, () -> player.sendMessage(Texts.prefixed("message.neoskies.home.no_island"))); } - - static void run(ServerPlayerEntity visitor, String islandOwner) { - IslandLogic.getInstance().islands.getByPlayer(islandOwner).ifPresentOrElse(island -> { - if (visitor.getWorld().getRegistryKey().getValue().equals(NeoSkies.id(island.owner.uuid.toString())) && !IslandLogic.getConfig().allowVisitCurrentIsland) { - visitor.sendMessage(Texts.prefixed("message.neoskies.visit_home.fail", map -> map.put("owner", islandOwner))); - } else { - if (island.isMember(visitor)) { - visitor.sendMessage(Texts.prefixed("message.neoskies.visit_home.success", map -> map.put("owner", islandOwner))); - island.visitAsMember(visitor); - } else { - visitor.sendMessage(Texts.prefixed("message.neoskies.visit_home.not_member")); - } - } - }, () -> { - visitor.sendMessage(Texts.prefixed("message.neoskies.visit_home.no_island")); - }); - } } diff --git a/src/main/java/com/awakenedredstone/neoskies/command/island/VisitCommand.java b/src/main/java/com/awakenedredstone/neoskies/command/island/VisitCommand.java index 4e0b9cf..d7ff07d 100644 --- a/src/main/java/com/awakenedredstone/neoskies/command/island/VisitCommand.java +++ b/src/main/java/com/awakenedredstone/neoskies/command/island/VisitCommand.java @@ -4,10 +4,12 @@ import com.awakenedredstone.neoskies.logic.IslandLogic; import com.awakenedredstone.neoskies.util.Texts; import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; import me.lucko.fabric.api.permissions.v0.Permissions; import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; import static com.awakenedredstone.neoskies.command.utils.CommandUtils.node; import static com.awakenedredstone.neoskies.command.utils.CommandUtils.register; @@ -21,10 +23,16 @@ public static void init(CommandDispatcher dispatcher) { register(dispatcher, node() .then(literal("visit") .requires(Permissions.require("neoskies.island.visit", true)) - .then(argument("player", player()) + .then(argument("player", StringArgumentType.word()) + .suggests((context, builder) -> { + for (String playerName : context.getSource().getServer().getPlayerManager().getPlayerNames()) { + builder.suggest(playerName); + } + return builder.buildFuture(); + }) .executes(context -> { var visitor = context.getSource().getPlayer(); - var owner = EntityArgumentType.getPlayer(context, "player"); + var owner = StringArgumentType.getString(context, "player"); if (visitor != null && owner != null) { VisitCommand.run(visitor, owner); } @@ -35,25 +43,23 @@ public static void init(CommandDispatcher dispatcher) { ); } - static void run(ServerPlayerEntity visitor, ServerPlayerEntity owner) { - String ownerName = owner.getName().getString(); - + static void run(ServerPlayerEntity visitor, String owner) { IslandLogic.getInstance().islands.getByPlayer(owner).ifPresentOrElse(island -> { if (!island.isMember(visitor) && island.isBanned(visitor)) { - visitor.sendMessage(Texts.prefixed("message.neoskies.island_visit.ban", map -> map.put("owner", ownerName))); + visitor.sendMessage(Texts.prefixed("message.neoskies.island_visit.ban", map -> map.put("owner", owner))); } else { if (!island.locked) { if (visitor.getWorld().getRegistryKey().getValue().equals(NeoSkies.id(island.owner.uuid.toString())) && !IslandLogic.getConfig().allowVisitCurrentIsland) { - visitor.sendMessage(Texts.prefixed("message.neoskies.island_visit.fail", map -> map.put("owner", ownerName))); + visitor.sendMessage(Texts.prefixed("message.neoskies.island_visit.fail", map -> map.put("owner", owner))); } else { - visitor.sendMessage(Texts.prefixed("message.neoskies.island_visit.success", map -> map.put("owner", ownerName))); + visitor.sendMessage(Texts.prefixed("message.neoskies.island_visit.success", map -> map.put("owner", owner))); island.visitAsVisitor(visitor); } } else { - visitor.sendMessage(Texts.prefixed("message.neoskies.island_visit.no_visits", map -> map.put("owner", ownerName))); + visitor.sendMessage(Texts.prefixed("message.neoskies.island_visit.no_visits", map -> map.put("owner", owner))); } } - }, () -> visitor.sendMessage(Texts.prefixed("message.neoskies.island_visit.no_island", map -> map.put("owner", ownerName)))); + }, () -> visitor.sendMessage(Texts.prefixed("message.neoskies.island_visit.no_island", map -> map.put("owner", owner)))); } } diff --git a/src/main/java/com/awakenedredstone/neoskies/config/IslandRankingConfig.java b/src/main/java/com/awakenedredstone/neoskies/config/IslandRankingConfig.java index 7306f91..8fe0157 100644 --- a/src/main/java/com/awakenedredstone/neoskies/config/IslandRankingConfig.java +++ b/src/main/java/com/awakenedredstone/neoskies/config/IslandRankingConfig.java @@ -9,19 +9,12 @@ import com.awakenedredstone.neoskies.config.source.annotation.SkipThis; import com.awakenedredstone.neoskies.mixin.accessor.TagEntryAccessor; import com.google.gson.JsonElement; -import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.JsonOps; -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.block.ButtonBlock; -import net.minecraft.client.gui.screen.option.KeybindsScreen; import net.minecraft.registry.Registries; import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.tag.TagEntry; import net.minecraft.registry.tag.TagKey; -import net.minecraft.text.Text; -import net.minecraft.text.TranslatableTextContent; import net.minecraft.util.Identifier; import java.util.HashMap; diff --git a/src/main/java/com/awakenedredstone/neoskies/logic/Hub.java b/src/main/java/com/awakenedredstone/neoskies/logic/Hub.java index cc5893b..988fce4 100644 --- a/src/main/java/com/awakenedredstone/neoskies/logic/Hub.java +++ b/src/main/java/com/awakenedredstone/neoskies/logic/Hub.java @@ -2,6 +2,7 @@ import com.awakenedredstone.neoskies.api.events.IslandEvents; import com.awakenedredstone.neoskies.util.Texts; +import com.awakenedredstone.neoskies.util.Worlds; import net.fabricmc.fabric.api.dimension.v1.FabricDimensions; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; @@ -14,14 +15,14 @@ public class Hub { public boolean hasProtection = false; //public PositionSongPlayer songPlayer = null; - public void visit(PlayerEntity player) { + public void visit(ServerPlayerEntity player) { visit(player, false); } - public void visit(PlayerEntity player, boolean silent) { + public void visit(ServerPlayerEntity player, boolean silent) { var world = IslandLogic.getServer().getOverworld(); if (!silent) player.sendMessage(Texts.prefixed("message.neoskies.hub_visit")); - FabricDimensions.teleport(player, world, new TeleportTarget(this.pos, new Vec3d(0, 0, 0), 0, 0)); + Worlds.teleport(player, world, this.pos, 0, 0); IslandEvents.ON_HUB_VISIT.invoker().invoke(player, world); } diff --git a/src/main/java/com/awakenedredstone/neoskies/logic/Island.java b/src/main/java/com/awakenedredstone/neoskies/logic/Island.java index 24a5cde..8bac4c9 100644 --- a/src/main/java/com/awakenedredstone/neoskies/logic/Island.java +++ b/src/main/java/com/awakenedredstone/neoskies/logic/Island.java @@ -11,12 +11,15 @@ import com.awakenedredstone.neoskies.util.Constants; import com.awakenedredstone.neoskies.util.Players; import com.awakenedredstone.neoskies.util.Texts; +import com.awakenedredstone.neoskies.util.Worlds; import eu.pb4.common.economy.api.EconomyAccount; import net.minecraft.block.Block; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; +import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKeys; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.structure.StructurePlacementData; import net.minecraft.structure.StructureTemplate; @@ -27,6 +30,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.random.RandomSeed; import net.minecraft.world.Difficulty; +import net.minecraft.world.World; import net.minecraft.world.biome.BiomeKeys; import net.minecraft.world.dimension.DimensionTypes; import net.minecraft.world.gen.chunk.FlatChunkGenerator; @@ -308,14 +312,7 @@ public boolean isInteractionAllowed(Identifier identifier, PermissionLevel sourc return source.getLevel() >= settings.getPermissionLevel().getLevel(); } - public RuntimeWorldHandle getOverworldHandler() { - if (this.islandConfig == null) { - this.islandConfig = createIslandConfig(); - } - return this.fantasy.getOrOpenPersistentWorld(NeoSkies.id(this.owner.uuid.toString()), this.islandConfig); - } - - private RuntimeWorldConfig createIslandConfig() { + private RuntimeWorldConfig createOverworldConfig() { var biome = IslandLogic.getServer().getRegistryManager().get(RegistryKeys.BIOME).getEntry(IslandLogic.getServer().getRegistryManager().get(RegistryKeys.BIOME).getOrThrow(BiomeKeys.PLAINS)); FlatChunkGeneratorConfig flat = new FlatChunkGeneratorConfig(Optional.empty(), biome, List.of()); FlatChunkGenerator generator = new FlatChunkGenerator(flat); @@ -329,13 +326,6 @@ private RuntimeWorldConfig createIslandConfig() { .setSeed(0L); } - public RuntimeWorldHandle getNetherHandler() { - if (this.netherConfig == null) { - this.netherConfig = createNetherConfig(); - } - return this.fantasy.getOrOpenPersistentWorld(new Identifier(Constants.NAMESPACE_NETHER, this.owner.uuid.toString()), this.netherConfig); - } - private RuntimeWorldConfig createNetherConfig() { var biome = IslandLogic.getServer().getRegistryManager().get(RegistryKeys.BIOME).getEntry(IslandLogic.getServer().getRegistryManager().get(RegistryKeys.BIOME).getOrThrow(BiomeKeys.NETHER_WASTES)); FlatChunkGeneratorConfig flat = new FlatChunkGeneratorConfig(Optional.empty(), biome, List.of()); @@ -349,13 +339,6 @@ private RuntimeWorldConfig createNetherConfig() { .setSeed(RandomSeed.getSeed()); } - public RuntimeWorldHandle getEndHandler() { - if (this.endConfig == null) { - this.endConfig = createEndConfig(); - } - return this.fantasy.getOrOpenPersistentWorld(new Identifier(Constants.NAMESPACE_END, this.owner.uuid.toString()), this.endConfig); - } - private RuntimeWorldConfig createEndConfig() { var biome = IslandLogic.getServer().getRegistryManager().get(RegistryKeys.BIOME).getEntry(IslandLogic.getServer().getRegistryManager().get(RegistryKeys.BIOME).getOrThrow(BiomeKeys.THE_END)); FlatChunkGeneratorConfig flat = new FlatChunkGeneratorConfig(Optional.empty(), biome, List.of()); @@ -369,6 +352,27 @@ private RuntimeWorldConfig createEndConfig() { .setSeed(RandomSeed.getSeed()); } + public RuntimeWorldHandle getOverworldHandler() { + if (this.islandConfig == null) { + this.islandConfig = createOverworldConfig(); + } + return this.fantasy.getOrOpenPersistentWorld(NeoSkies.id(this.owner.uuid.toString()), this.islandConfig); + } + + public RuntimeWorldHandle getNetherHandler() { + if (this.netherConfig == null) { + this.netherConfig = createNetherConfig(); + } + return this.fantasy.getOrOpenPersistentWorld(new Identifier(Constants.NAMESPACE_NETHER, this.owner.uuid.toString()), this.netherConfig); + } + + public RuntimeWorldHandle getEndHandler() { + if (this.endConfig == null) { + this.endConfig = createEndConfig(); + } + return this.fantasy.getOrOpenPersistentWorld(new Identifier(Constants.NAMESPACE_END, this.owner.uuid.toString()), this.endConfig); + } + public ServerWorld getOverworld() { RuntimeWorldHandle handler = this.getOverworldHandler(); handler.setTickWhenEmpty(false); @@ -391,6 +395,18 @@ public ServerWorld getNether() { return world; } + public RegistryKey getOverworldKey() { + return getOverworld().getRegistryKey(); + } + + public RegistryKey getNetherKey() { + return getNether().getRegistryKey(); + } + + public RegistryKey getEndKey() { + return getEnd().getRegistryKey(); + } + public void updateBlocks(@Nullable Map blocks) { if (blocks != null) this.blocks = blocks; this.points = 0; @@ -400,9 +416,9 @@ public void updateBlocks(@Nullable Map blocks) { }); } - public void visit(PlayerEntity player, Vec3d pos) { + public void visit(ServerPlayerEntity player, Vec3d pos) { ServerWorld world = this.getOverworld(); - player.teleport(world, pos.getX(), pos.getY(), pos.getZ(), Set.of(), 0, 0); + Worlds.teleport(player, world, pos.getX(), pos.getY(), pos.getZ(), 0, 0); if (!isMember(player)) { Players.get(this.owner.name).ifPresent(owner -> { @@ -420,11 +436,11 @@ public void visit(PlayerEntity player, Vec3d pos) { } } - public void visitAsMember(PlayerEntity player) { + public void visitAsMember(ServerPlayerEntity player) { this.visit(player, this.spawnPos); } - public void visitAsVisitor(PlayerEntity player) { + public void visitAsVisitor(ServerPlayerEntity player) { this.visit(player, this.visitsPos); } diff --git a/src/main/java/com/awakenedredstone/neoskies/logic/IslandStuck.java b/src/main/java/com/awakenedredstone/neoskies/logic/IslandStuck.java index 201b74e..123c522 100644 --- a/src/main/java/com/awakenedredstone/neoskies/logic/IslandStuck.java +++ b/src/main/java/com/awakenedredstone/neoskies/logic/IslandStuck.java @@ -99,6 +99,17 @@ public Optional getByPlayer(UUID playerUuid) { return Optional.empty(); } + public Optional getById(String islandId) { + return getById(UUID.fromString(islandId)); + } + + public Optional getById(UUID islandId) { + for (var island : this.stuck) { + if (island.getIslandId().equals(islandId)) return Optional.of(island); + } + return Optional.empty(); + } + public Optional get(UUID islandId) { for (var island : this.stuck) { if (island.getIslandId().equals(islandId)) return Optional.of(island); diff --git a/src/main/java/com/awakenedredstone/neoskies/logic/registry/NeoSkiesIslandSettings.java b/src/main/java/com/awakenedredstone/neoskies/logic/registry/NeoSkiesIslandSettings.java index ead5e80..db5302b 100644 --- a/src/main/java/com/awakenedredstone/neoskies/logic/registry/NeoSkiesIslandSettings.java +++ b/src/main/java/com/awakenedredstone/neoskies/logic/registry/NeoSkiesIslandSettings.java @@ -39,7 +39,7 @@ public class NeoSkiesIslandSettings { public static final IslandSettings USE_LODESTONE = register("use/lodestone", Items.LODESTONE); public static final IslandSettings USE_REDSTONE = register("use/redstone", Items.REDSTONE); public static final IslandSettings USE_RESPAWN_ANCHOR = register("use/respawn_anchor", Items.RESPAWN_ANCHOR); - public static final IslandSettings USE_SIGNS = register("use/signs", Items.SPAWNER); + public static final IslandSettings USE_SIGNS = register("use/signs", Items.OAK_SIGN); public static final IslandSettings USE_SPAWNER = register("use/spawner", Items.SPAWNER); public static final IslandSettings USE_TNT = register("use/tnt", Items.TNT); @@ -51,7 +51,7 @@ public class NeoSkiesIslandSettings { public static final IslandSettings HARVEST = register("harvest", Items.SWEET_BERRIES); public static final IslandSettings RIDE_MINECARTS = register("ride/minecarts", Items.MINECART); - public static final IslandSettings RIDE_BOATS = register("ride/boats", Items.MINECART); + public static final IslandSettings RIDE_BOATS = register("ride/boats", Items.OAK_BOAT); public static final IslandSettings RIDE_OTHERS = register("ride/others", Items.SADDLE); public static final IslandSettings LEASH_ENTITY = register("leash/entity", Items.LEAD); public static final IslandSettings SHEAR_ENTITY = register("shear/entity", Items.SHEARS); diff --git a/src/main/java/com/awakenedredstone/neoskies/mixin/block/EndPortalBlockMixin.java b/src/main/java/com/awakenedredstone/neoskies/mixin/block/EndPortalBlockMixin.java index 2a3892a..d1b2bd0 100644 --- a/src/main/java/com/awakenedredstone/neoskies/mixin/block/EndPortalBlockMixin.java +++ b/src/main/java/com/awakenedredstone/neoskies/mixin/block/EndPortalBlockMixin.java @@ -3,43 +3,41 @@ import com.awakenedredstone.neoskies.api.NeoSkiesAPI; import com.awakenedredstone.neoskies.logic.Island; import com.awakenedredstone.neoskies.logic.IslandLogic; -import net.minecraft.block.BlockState; +import com.llamalad7.mixinextras.sugar.Local; import net.minecraft.block.EndPortalBlock; -import net.minecraft.entity.Entity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; +import net.minecraft.registry.RegistryKey; import net.minecraft.world.World; 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; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.spongepowered.asm.mixin.injection.ModifyVariable; import java.util.Optional; @Mixin(EndPortalBlock.class) public class EndPortalBlockMixin { - @Inject(method = "onEntityCollision", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;moveToWorld(Lnet/minecraft/server/world/ServerWorld;)Lnet/minecraft/entity/Entity;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) - public void resourceKey(BlockState state, World world, BlockPos pos, Entity entity, CallbackInfo ci) { + @ModifyVariable(method = "onEntityCollision", at = @At(value = "STORE"), ordinal = 0) + public RegistryKey resourceKey(RegistryKey original, @Local(argsOnly = true) World world) { if (NeoSkiesAPI.isIsland(world)) { + Optional island = NeoSkiesAPI.getIsland(world); if (!IslandLogic.getConfig().enableEndIsland) { - ci.cancel(); - return; + if (island.isPresent()) { + return island.get().getOverworldKey(); + } else { + return world.getRegistryKey(); + } } - Optional island = NeoSkiesAPI.getIsland(world); if (island.isPresent()) { - ServerWorld targetWorld; + RegistryKey targetWorld; if (NeoSkiesAPI.isEnd(world.getRegistryKey())) { - targetWorld = island.get().getOverworld(); + targetWorld = island.get().getOverworldKey(); } else { - targetWorld = island.get().getEnd(); - } - if (targetWorld != null) { - entity.moveToWorld(targetWorld); + targetWorld = island.get().getEndKey(); } - ci.cancel(); + return targetWorld; } } + + return original; } } diff --git a/src/main/java/com/awakenedredstone/neoskies/mixin/entity/EntityAccessor.java b/src/main/java/com/awakenedredstone/neoskies/mixin/entity/EntityAccessor.java new file mode 100644 index 0000000..7c38dde --- /dev/null +++ b/src/main/java/com/awakenedredstone/neoskies/mixin/entity/EntityAccessor.java @@ -0,0 +1,10 @@ +package com.awakenedredstone.neoskies.mixin.entity; + +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(Entity.class) +public interface EntityAccessor { + @Invoker void callUnsetRemoved(); +} diff --git a/src/main/java/com/awakenedredstone/neoskies/mixin/entity/PlayerManagerMixin.java b/src/main/java/com/awakenedredstone/neoskies/mixin/entity/PlayerManagerMixin.java index ae966ba..17bdda6 100644 --- a/src/main/java/com/awakenedredstone/neoskies/mixin/entity/PlayerManagerMixin.java +++ b/src/main/java/com/awakenedredstone/neoskies/mixin/entity/PlayerManagerMixin.java @@ -104,7 +104,11 @@ private void loadIsland(ClientConnection connection, ServerPlayerEntity player, @ModifyExpressionValue(method = "respawnPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;getSpawnPointDimension()Lnet/minecraft/registry/RegistryKey;")) private RegistryKey neoskies$fixRespawnDimension(RegistryKey original, ServerPlayerEntity player) { - return player.getWorld().getRegistryKey(); + World playerWorld = player.getWorld(); + if (NeoSkiesAPI.isIsland(playerWorld)) { + return NeoSkiesAPI.getIsland(playerWorld).get().getOverworldKey(); + } + return IslandLogic.getServer().getOverworld().getRegistryKey(); } @Redirect(method = "respawnPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;findRespawnPosition(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/util/math/BlockPos;FZZ)Ljava/util/Optional;")) diff --git a/src/main/java/com/awakenedredstone/neoskies/mixin/entity/ServerPlayerEntityAccessor.java b/src/main/java/com/awakenedredstone/neoskies/mixin/entity/ServerPlayerEntityAccessor.java new file mode 100644 index 0000000..b89a49c --- /dev/null +++ b/src/main/java/com/awakenedredstone/neoskies/mixin/entity/ServerPlayerEntityAccessor.java @@ -0,0 +1,11 @@ +package com.awakenedredstone.neoskies.mixin.entity; + +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ServerPlayerEntity.class) +public interface ServerPlayerEntityAccessor { + @Invoker void callWorldChanged(ServerWorld world); +} diff --git a/src/main/java/com/awakenedredstone/neoskies/mixin/entity/ServerPlayerEntityMixin.java b/src/main/java/com/awakenedredstone/neoskies/mixin/entity/ServerPlayerEntityMixin.java index cb10979..bd04bf9 100644 --- a/src/main/java/com/awakenedredstone/neoskies/mixin/entity/ServerPlayerEntityMixin.java +++ b/src/main/java/com/awakenedredstone/neoskies/mixin/entity/ServerPlayerEntityMixin.java @@ -5,6 +5,7 @@ import com.awakenedredstone.neoskies.event.PlayerEvents; import com.awakenedredstone.neoskies.util.Worlds; import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Local; import com.mojang.authlib.GameProfile; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.player.PlayerEntity; @@ -21,8 +22,6 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ServerPlayerEntity.class) @@ -73,6 +72,7 @@ public RegistryKey getTeleportTarget_redirectRegistryKey(RegistryKey worldChanged_redirectRegistryKey(RegistryKey world) { return Worlds.redirect(world); } + @ModifyExpressionValue(method = "createCommonPlayerSpawnInfo", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;getRegistryKey()Lnet/minecraft/registry/RegistryKey;")) public RegistryKey createCommonPlayerSpawnInfo_redirectRegistryKey(RegistryKey world) { return Worlds.redirect(world); diff --git a/src/main/java/com/awakenedredstone/neoskies/util/Worlds.java b/src/main/java/com/awakenedredstone/neoskies/util/Worlds.java index f0c57b6..2e4e96c 100644 --- a/src/main/java/com/awakenedredstone/neoskies/util/Worlds.java +++ b/src/main/java/com/awakenedredstone/neoskies/util/Worlds.java @@ -4,12 +4,19 @@ import com.awakenedredstone.neoskies.logic.Hub; import com.awakenedredstone.neoskies.logic.Island; import com.awakenedredstone.neoskies.logic.IslandLogic; +import com.awakenedredstone.neoskies.mixin.entity.EntityAccessor; +import com.awakenedredstone.neoskies.mixin.entity.ServerPlayerEntityAccessor; import net.fabricmc.fabric.api.dimension.v1.FabricDimensions; +import net.minecraft.entity.Entity; +import net.minecraft.network.packet.s2c.play.DifficultyS2CPacket; +import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; import net.minecraft.registry.RegistryKey; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.Vec3d; import net.minecraft.world.TeleportTarget; import net.minecraft.world.World; +import net.minecraft.world.WorldProperties; import java.util.Optional; @@ -53,4 +60,36 @@ public static RegistryKey redirect(RegistryKey registryKey) { return registryKey; } + public static RegistryKey redirect(World world) { + return redirect(world.getRegistryKey()); + } + + public static void teleport(ServerPlayerEntity player, ServerWorld targetWorld, Vec3d pos, float yaw, float pitch) { + teleport(player, targetWorld, pos.x, pos.y, pos.z, yaw, pitch); + } + + public static void teleport(ServerPlayerEntity player, ServerWorld targetWorld, double x, double y, double z, float yaw, float pitch) { + player.setCameraEntity(player); + player.stopRiding(); + if (targetWorld == player.getWorld()) { + player.networkHandler.requestTeleport(x, y, z, yaw, pitch); + } else { + ServerWorld serverWorld = player.getServerWorld(); + WorldProperties worldProperties = targetWorld.getLevelProperties(); + if (!redirect(targetWorld).equals(redirect(player.getWorld()))) { + player.networkHandler.sendPacket(new PlayerRespawnS2CPacket(player.createCommonPlayerSpawnInfo(targetWorld), PlayerRespawnS2CPacket.KEEP_ALL)); + } + player.networkHandler.sendPacket(new DifficultyS2CPacket(worldProperties.getDifficulty(), worldProperties.isDifficultyLocked())); + player.server.getPlayerManager().sendCommandTree(player); + serverWorld.removePlayer(player, Entity.RemovalReason.CHANGED_DIMENSION); + ((EntityAccessor) player).callUnsetRemoved(); + player.refreshPositionAndAngles(x, y, z, yaw, pitch); + player.setServerWorld(targetWorld); + targetWorld.onPlayerTeleport(player); + ((ServerPlayerEntityAccessor) player).callWorldChanged(serverWorld); + player.networkHandler.requestTeleport(x, y, z, yaw, pitch); + player.server.getPlayerManager().sendWorldInfo(player, targetWorld); + player.server.getPlayerManager().sendPlayerStatus(player); + } + } } diff --git a/src/main/resources/data/neoskies/lang/en_us.json b/src/main/resources/data/neoskies/lang/en_us.json index 321cca4..86d5ff5 100644 --- a/src/main/resources/data/neoskies/lang/en_us.json +++ b/src/main/resources/data/neoskies/lang/en_us.json @@ -125,7 +125,7 @@ "island_settings.neoskies.ride/others.description": "Allows players to ride mobs", "island_settings.neoskies.leash/entity.description": "Allows players to leash entities", "island_settings.neoskies.shear/entity.description": "Allows players to shear entities", - "island_settings.neoskies.bucket/passive.description": "Allow players to bucket passive mobs", + "island_settings.neoskies.bucket/passive.description": "Allow players to bucket passive mobs", "island_settings.neoskies.harvest.description": "Allows players to harvest crops", "island_settings/selected": "> %level%", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 90cf3fd..d1a1793 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -20,10 +20,18 @@ ], "cardinal-components": [ "com.awakenedredstone.neoskies.data.NeoSkiesComponents" + ], + + "client": [ + "com.awakenedredstone.neoskies.NeoSkiesClient" ] }, "mixins": [ - "neoskies.mixins.json" + "neoskies.mixins.json", + { + "config": "neoskies.client.mixins.json", + "environment": "client" + } ], "custom": { "cardinal-components": [ diff --git a/src/main/resources/neoskies.mixins.json b/src/main/resources/neoskies.mixins.json index 458e634..1b9021c 100644 --- a/src/main/resources/neoskies.mixins.json +++ b/src/main/resources/neoskies.mixins.json @@ -14,8 +14,10 @@ "compat.JanksonAcessor", "compat.POJODeserializerAccessor", "entity.DataTrackerAccessor", + "entity.EntityAccessor", "entity.EntityMixin", "entity.PlayerManagerMixin", + "entity.ServerPlayerEntityAccessor", "entity.ServerPlayerEntityMixin", "item.BoneMealItemMixin", "item.ItemStackMixin", diff --git a/src/testmod/resources/fabric.mod.json b/src/testmod/resources/fabric.mod.json index 8b780b9..8699078 100644 --- a/src/testmod/resources/fabric.mod.json +++ b/src/testmod/resources/fabric.mod.json @@ -3,9 +3,11 @@ "id": "neoskies-test", "version": "${version}", "name": "NeoSkies TestMod", - "description": "Library to work with server-side events with the ability to filter by event source", - "authors": ["Nucleoid Contributors"], - "license": "LGPLv3", + "description": "The testmod for NeoSkies | Also includes devtools", + "authors": [ + "Awakened Redstone" + ], + "license": "LGPL-3.0", "environment": "*", "entrypoints": { "main": [ diff --git a/src/testmodClient/java/com/awakenedredstone/neoskies/test/DebugDearImGuiEntrypoint.java b/src/testmodClient/java/com/awakenedredstone/neoskies/test/DebugDearImGuiEntrypoint.java new file mode 100644 index 0000000..5393104 --- /dev/null +++ b/src/testmodClient/java/com/awakenedredstone/neoskies/test/DebugDearImGuiEntrypoint.java @@ -0,0 +1,17 @@ +package com.awakenedredstone.neoskies.test; + +import dev.deftu.imgui.DearImGuiEntrypoint; +import dev.deftu.imgui.ImGuiRenderer; + +public class DebugDearImGuiEntrypoint implements DearImGuiEntrypoint { + + @Override + public ImGuiRenderer createRenderer() { + return new DebugImGuiRenderer(); + } + + @Override + public void render() { + // Render ImGui here + } +} diff --git a/src/testmodClient/java/com/awakenedredstone/neoskies/test/DebugImGuiRenderer.java b/src/testmodClient/java/com/awakenedredstone/neoskies/test/DebugImGuiRenderer.java new file mode 100644 index 0000000..5a80263 --- /dev/null +++ b/src/testmodClient/java/com/awakenedredstone/neoskies/test/DebugImGuiRenderer.java @@ -0,0 +1,176 @@ +package com.awakenedredstone.neoskies.test; + +import com.awakenedredstone.neoskies.logic.Island; +import com.awakenedredstone.neoskies.logic.IslandLogic; +import com.awakenedredstone.neoskies.util.MapBuilder; +import com.awakenedredstone.neoskies.util.Texts; +import com.awakenedredstone.neoskies.util.UnitConvertions; +import dev.deftu.imgui.ImGuiRenderer; +import imgui.ImGui; +import imgui.extension.implot.ImPlot; +import imgui.extension.implot.ImPlotContext; +import imgui.extension.implot.flag.ImPlotStyleVar; +import imgui.flag.ImGuiCond; +import imgui.flag.ImGuiWindowFlags; +import imgui.type.ImBoolean; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.text.Text; + +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +public class DebugImGuiRenderer implements ImGuiRenderer { + private static final ImPlotContext IMPLOT_CONTEXT; + public static final ImBoolean OPEN = new ImBoolean(true); + private static final Map MESSAGES = new HashMap<>(); + + static { + IMPLOT_CONTEXT = ImPlot.createContext(); + } + + public static int bufferLength = 600; + public static final List MEMORY = new LinkedList<>() { + @Override + public boolean add(Long aFloat) { + if (this.size() >= 10000) { + this.removeFirst(); + } + return super.add(aFloat); + } + }; + + @Override + public void render() { + if (!OPEN.get()) return; + + /*ImPlot.showDemoWindow(OPEN); + ImGui.showDemoWindow();*/ + + ImGui.setNextWindowSize(600, 750, ImGuiCond.FirstUseEver); + if (ImGui.begin("NeoSkies debug tools", OPEN, ImGuiWindowFlags.MenuBar)) { + if (MinecraftClient.getInstance().player != null && IslandLogic.getInstance() != null) { + ImGui.text(IslandLogic.getServer().getPlayerManager().getPlayer(MinecraftClient.getInstance().player.getUuid()).getWorld().getRegistryKey().getValue().toString()); + ImGui.text(String.valueOf(MinecraftClient.getInstance().player.getWorld().getWorldBorder().getSize())); + } + + if (ImGui.collapsingHeader("Server RAM")) { + final Float[] samples = new Float[bufferLength]; + Arrays.fill(samples, 0f); + + final Float[] samples2 = new Float[bufferLength]; + for (int i = 0; i < samples.length; i++) { + try { + if (MEMORY.size() < samples.length && i < MEMORY.size()) { + samples[samples.length - MEMORY.size() + i] = (float) toMiB(MEMORY.get(i)); + } else if (i < MEMORY.size()) { + samples[i] = (float) toMiB(MEMORY.get(Math.max(0, MEMORY.size() - bufferLength) + i)); + } + samples2[i] = (float) i; + } catch (Throwable ignored) {} + } + + if (ImGui.button("Clear")) { + MEMORY.clear(); + } + ImGui.sameLine(); + + ImGui.text("Buffer size: %s".formatted(formatSeconds(bufferLength / 10))); + ImGui.sameLine(); + if (ImGui.button("+")) { + if (Screen.hasShiftDown()) { + bufferLength += 100; + } else { + bufferLength += 10; + } + } + ImGui.sameLine(); + if (ImGui.button("-")) { + if (Screen.hasShiftDown()) { + bufferLength -= 100; + } else { + bufferLength -= 10; + } + } + + long maxMemory = Runtime.getRuntime().maxMemory(); + long totalMemory = Runtime.getRuntime().totalMemory(); + long freeMemory = Runtime.getRuntime().freeMemory(); + long usedMemory = totalMemory - freeMemory; + ImGui.text("Memory: %s%% (%s/%sMiB)".formatted(usedMemory * 100L / maxMemory, toMiB(usedMemory), toMiB(maxMemory))); + + ImPlot.setNextPlotLimits(0, bufferLength, 0, toMiB(maxMemory), ImGuiCond.Always); + if (ImPlot.beginPlot("Example Plot")) { + ImPlot.pushStyleVar(ImPlotStyleVar.FillAlpha, 0.25f); + try { + ImPlot.plotLine("Line", samples2, samples); + ImPlot.plotShaded("Line", samples2, samples, 0, bufferLength); + } catch (Throwable ignored) {} + ImPlot.endPlot(); + } + } + + if (ImGui.collapsingHeader("Islands")) { + if (MESSAGES.containsKey("island.info")) { + ImGui.text(MESSAGES.get("island.info").getString()); + } + + for (Island island : IslandLogic.getInstance().islands.stuck) { + if (ImGui.button("Scan " + island.hashCode())) { //Each button must have a unique id, and the id is the label ._. + if (island.isScanning()) { + MESSAGES.put("island.info", Texts.of("Can not queue a scan for an island that is already scanning!")); + } else { + MESSAGES.put("island.info", Texts.of("Scan queued")); + + AtomicInteger total = new AtomicInteger(); + IslandLogic.getInstance().islandScanner.queueScan(island, integer -> { + MESSAGES.put("island.info", Texts.of("Scanning %total% chunks", new MapBuilder.StringMap().putAny("total", integer).build())); + total.set(integer); + }, integer -> { + MESSAGES.put("island.info", Texts.of("Scanned %current%/%total% chunks", new MapBuilder.StringMap() + .putAny("total", total.get()) + .putAny("current", integer) + .build())); + }, (timeTaken, scannedBlocks) -> { + MESSAGES.put("island.info", Texts.of("Scanned %total% blocks in %time%", new MapBuilder.StringMap() + .putAny("total", UnitConvertions.readableNumber(scannedBlocks.values().stream().mapToInt(value -> value).sum())) + .putAny("time", UnitConvertions.formatTimings(timeTaken)) + .build())); + }, () -> { + MESSAGES.put("island.info", Texts.of("Island scan failed")); + }); + } + } + ImGui.sameLine(); + ImGui.text("%s: %s (%s)".formatted(island.owner.name, island.getIslandId(), island.getPoints())); + } + } + + ImGui.end(); + } + } + + private static long toMiB(long bytes) { + return bytes / 1024L / 1024L; + } + + private static String formatSeconds(int seconds) { + StringBuilder builder = new StringBuilder(); + if (seconds >= 60) { + int minutes = seconds / 60; + if (minutes >= 60) { + int hours = minutes / 60; + builder.append(hours).append("h"); + } + if (minutes % 60 > 0) { + builder.append(minutes % 60).append("m"); + } + } + + if (seconds % 60 > 0) { + builder.append(seconds % 60).append("s"); + } + + return builder.toString(); + } +} diff --git a/src/testmodClient/java/com/awakenedredstone/neoskies/test/NeoSkiesTestClientMain.java b/src/testmodClient/java/com/awakenedredstone/neoskies/test/NeoSkiesTestClientMain.java new file mode 100644 index 0000000..61e0ef7 --- /dev/null +++ b/src/testmodClient/java/com/awakenedredstone/neoskies/test/NeoSkiesTestClientMain.java @@ -0,0 +1,30 @@ +package com.awakenedredstone.neoskies.test; + +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.ClientTickEvents; + +public final class NeoSkiesTestClientMain implements ClientModInitializer { + private static int tick = 0; + + @Override + public void onInitializeClient() { + ClientTickEvents.END_CLIENT_TICK.register(client -> { + if (tick++ % 2 == 0) { + DebugImGuiRenderer.MEMORY.add((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())); + } + }); + + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> { + dispatcher.register(ClientCommandManager.literal("sbac") + .then(ClientCommandManager.literal("debug") + .executes(context -> { + DebugImGuiRenderer.OPEN.set(true); + return 0; + }) + ) + ); + }); + } +} diff --git a/src/testmodClient/resources/fabric.mod.json b/src/testmodClient/resources/fabric.mod.json new file mode 100644 index 0000000..5a8525a --- /dev/null +++ b/src/testmodClient/resources/fabric.mod.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": 1, + "id": "neoskies-test-client", + "version": "${version}", + "name": "NeoSkies TestMod (Client Edition)", + "description": "The testmod for NeoSkies (client edition) | Also includes devtools", + "authors": [ + "Awakened Redstone" + ], + "license": "LGPL-3.0", + "environment": "client", + "mixins": [ + "neoskies.test.client.mixins.json" + ], + "entrypoints": { + "client": [ + "com.awakenedredstone.neoskies.test.NeoSkiesTestClientMain" + ], + "imgui": [ + "com.awakenedredstone.neoskies.test.DebugDearImGuiEntrypoint" + ] + } +} diff --git a/src/testmodClient/resources/neoskies.test.client.mixins.json b/src/testmodClient/resources/neoskies.test.client.mixins.json new file mode 100644 index 0000000..2f98377 --- /dev/null +++ b/src/testmodClient/resources/neoskies.test.client.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.awakenedredstone.neoskies.test.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + ], + "injectors": { + "defaultRequire": 1 + } +}