Skip to content

Commit

Permalink
Blueprint editor environments
Browse files Browse the repository at this point in the history
  • Loading branch information
andantet committed Nov 21, 2023
1 parent 1756210 commit 10ef208
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 58 deletions.
4 changes: 2 additions & 2 deletions src/main/kotlin/net/mcbrawls/blueprint/BlueprintMod.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
import net.fabricmc.fabric.api.resource.ResourceManagerHelper
import net.mcbrawls.blueprint.command.BlueprintCommand
import net.mcbrawls.blueprint.environment.BlueprintEnvironmentManager
import net.mcbrawls.blueprint.editor.BlueprintEditors
import net.mcbrawls.blueprint.network.BlueprintConfigC2SPacket
import net.mcbrawls.blueprint.player.BlueprintPlayerData.Companion.blueprintData
import net.mcbrawls.blueprint.resource.BlueprintManager
Expand All @@ -24,7 +24,7 @@ object BlueprintMod : ModInitializer {
logger.info("Initializing $MOD_NAME")

// initialize classes
BlueprintEnvironmentManager
BlueprintEditors

// register config packet receiver
ServerPlayNetworking.registerGlobalReceiver(BlueprintConfigC2SPacket.TYPE) { packet, player, _ ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,40 @@ package net.mcbrawls.blueprint.command

import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.context.CommandContext
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType
import net.fabricmc.loader.api.FabricLoader
import net.fabricmc.loader.api.ModContainer
import net.fabricmc.loader.api.Version
import net.fabricmc.loader.api.metadata.ModMetadata
import net.mcbrawls.blueprint.BlueprintMod
import net.mcbrawls.blueprint.BlueprintMod.MOD_NAME
import net.mcbrawls.blueprint.editor.BlueprintEditors
import net.mcbrawls.blueprint.resource.BlueprintManager
import net.minecraft.command.argument.IdentifierArgumentType
import net.minecraft.server.command.CommandManager.argument
import net.minecraft.server.command.CommandManager.literal
import net.minecraft.server.command.ServerCommandSource
import net.minecraft.text.Text
import net.minecraft.util.Formatting
import net.minecraft.util.math.Vec2f
import net.minecraft.util.math.Vec3d

object BlueprintCommand {
const val BLUEPRINT_KEY = "blueprint"

private val INVALID_BLUEPRINT_EXCEPTION_TYPE = DynamicCommandExceptionType { id -> Text.literal("There is no blueprint with id \"$id\"") }

fun register(dispatcher: CommandDispatcher<ServerCommandSource>) {
val builder = literal("blueprint").executes(::execute)

//
builder.then(
literal("editor")
.then(
argument(BLUEPRINT_KEY, IdentifierArgumentType.identifier())
.suggests { _, suggestions -> BlueprintManager.suggestBlueprints(suggestions) }
.executes(::executeEditor)
)
)

dispatcher.register(builder)
}
Expand All @@ -36,4 +54,19 @@ object BlueprintCommand {
context.source.sendFeedback({ Text.literal("[$MOD_NAME] Version $version").formatted(Formatting.AQUA) }, false)
return 1
}

private fun executeEditor(context: CommandContext<ServerCommandSource>): Int {
val source = context.source
val player = source.playerOrThrow

val blueprintId = IdentifierArgumentType.getIdentifier(context, BLUEPRINT_KEY)
val environmentManager = BlueprintEditors[source.server]
val environment = environmentManager[blueprintId]

if (player.world !== environment) {
player.teleport(environment, Vec3d.ZERO, Vec2f.ZERO)
}

return 1
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
package net.mcbrawls.blueprint.environment
package net.mcbrawls.blueprint.editor

import dev.andante.bubble.world.BubbleWorld
import net.mcbrawls.blueprint.structure.Blueprint
import net.minecraft.registry.RegistryKey
import net.minecraft.server.MinecraftServer
import net.minecraft.util.Identifier
import net.minecraft.world.World
import net.minecraft.world.dimension.DimensionOptions

/**
* A custom world for managing blueprints.
*/
class BlueprintEnvironment(
class BlueprintEditorEnvironment(
/**
* The blueprint to manage.
*/
val blueprint: Blueprint,
val blueprintId: Identifier,

server: MinecraftServer,
key: RegistryKey<World>,
Expand Down
91 changes: 91 additions & 0 deletions src/main/kotlin/net/mcbrawls/blueprint/editor/BlueprintEditors.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package net.mcbrawls.blueprint.editor

import com.google.common.base.Preconditions
import dev.andante.bubble.BubbleManager
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents
import net.mcbrawls.blueprint.BlueprintMod
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.server.MinecraftServer
import net.minecraft.util.Identifier

/**
* Manages all blueprint editor environments for a server.
*/
class BlueprintEditors private constructor(private val server: MinecraftServer) {
/**
* All active blueprint editor environments.
*/
private val environments: MutableMap<Identifier, BlueprintEditorEnvironment> = mutableMapOf()

fun tick() {
}

fun clean() {
environments.values.forEach(BubbleManager.getOrCreate(server)::remove)
}

/**
* Gets or creates a blueprint environment for the given blueprint id.
* @return a blueprint environment
* @throws IllegalStateException if a world exists for the given blueprint id but that world is not an environment
*/
operator fun get(blueprintId: Identifier): BlueprintEditorEnvironment {
val blueprintNamespace = blueprintId.namespace
val blueprintPath = blueprintId.path
val worldId = Identifier(BlueprintMod.MOD_ID, "blueprint/$blueprintNamespace/$blueprintPath")
val worldKey = RegistryKey.of(RegistryKeys.WORLD, worldId)

val environmentWorld = server.getWorld(worldKey)

// get or create environment
val environment = if (environmentWorld != null) {
if (environmentWorld is BlueprintEditorEnvironment) {
environmentWorld
} else {
throw IllegalStateException("World existed for blueprint but was not environment: $blueprintId")
}
} else {
val bubbleManager = BubbleManager.getOrCreate(server)
val environment = bubbleManager.createAndInitialize(
identifier = worldId,
factory = { server, key, options -> BlueprintEditorEnvironment(blueprintId, server, key, options) }
)

environments[blueprintId] = environment
environment
}

return environment
}

companion object {
/**
* All blueprint environment managers.
*/
private val EDITORS = mutableMapOf<MinecraftServer, BlueprintEditors>()

init {
// register server events
ServerTickEvents.START_SERVER_TICK.register { server -> EDITORS[server]?.tick() }
ServerLifecycleEvents.SERVER_STOPPING.register { server -> EDITORS[server]?.clean() }
}

/**
* Gets an environment manager for the server or creates one if not present.
*/
operator fun get(server: MinecraftServer): BlueprintEditors {
Preconditions.checkState(server.isOnThread, "Cannot create blueprint environment manager off-thread")
return EDITORS.computeIfAbsent(server, ::BlueprintEditors)
}

/**
* Clears the environment manager for the given server.
*/
fun clear(server: MinecraftServer): BlueprintEditors? {
EDITORS[server]?.let(BlueprintEditors::clean)
return EDITORS.remove(server)
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.mcbrawls.blueprint.resource

import com.mojang.brigadier.suggestion.Suggestions
import com.mojang.brigadier.suggestion.SuggestionsBuilder
import net.fabricmc.fabric.api.resource.SimpleResourceReloadListener
import net.mcbrawls.blueprint.BlueprintMod
import net.mcbrawls.blueprint.structure.Blueprint
Expand Down Expand Up @@ -32,6 +34,23 @@ object BlueprintManager : SimpleResourceReloadListener<Map<Identifier, Blueprint
*/
private val blueprints: MutableMap<Identifier, Blueprint> = mutableMapOf()

/**
* Gets the blueprint with the given id.
* @return an optional blueprint
*/
operator fun get(id: Identifier): Blueprint? {
return blueprints[id]
}

/**
* Suggests all loaded blueprints to the suggestions builder.
* @return a suggestions future
*/
fun suggestBlueprints(builder: SuggestionsBuilder): CompletableFuture<Suggestions> {
blueprints.keys.map(Identifier::toString).forEach(builder::suggest)
return builder.buildFuture()
}

override fun load(
manager: ResourceManager,
profiler: Profiler,
Expand Down

0 comments on commit 10ef208

Please sign in to comment.