Skip to content

Commit

Permalink
Implement pack manager
Browse files Browse the repository at this point in the history
  • Loading branch information
andantet committed Feb 5, 2024
1 parent 5b48903 commit ffdac2b
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 30 deletions.
20 changes: 0 additions & 20 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,11 @@ repositories {
}
}

loom.splitEnvironmentSourceSets()

sourceSets {
test {
compileClasspath += main.compileClasspath
runtimeClasspath += main.runtimeClasspath
}

testClient {
compileClasspath += main.compileClasspath
runtimeClasspath += main.runtimeClasspath

compileClasspath += client.compileClasspath
runtimeClasspath += client.runtimeClasspath

compileClasspath += test.compileClasspath
runtimeClasspath += test.runtimeClasspath
}
}

dependencies {
Expand All @@ -65,13 +52,6 @@ loom {

accessWidenerPath = file("src/main/resources/${mod_id}.accesswidener")

mods {
mod_id {
sourceSet sourceSets.main
sourceSet sourceSets.client
}
}

runs {
client {
ideConfigGenerated(false)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package net.mcbrawls.packmanager;

import net.minecraft.network.packet.s2c.common.ResourcePackRemoveS2CPacket;
import net.minecraft.network.packet.s2c.common.ResourcePackSendS2CPacket;
import net.minecraft.server.MinecraftServer.ServerResourcePackProperties;

import java.util.Optional;
import java.util.Set;
import java.util.UUID;

/**
* Represents a context which can manage resource packs.
*/
public interface ResourcePackEnvironment {
/**
* Adds a resource pack to this environment.
* @param properties the resource pack properties
*/
default void addResourcePack(ServerResourcePackProperties properties) {
throw new AssertionError("Not implemented in mixin");
}

/**
* Removes a resource pack from this environment.
* @param uuid the uuid of the resource pack
*/
default void removeResourcePack(UUID uuid) {
throw new AssertionError("Not implemented in mixin");
}

/**
* Returns a set of all resource packs within this environment.
* @return a set of resource pack properties
*/
default Set<ServerResourcePackProperties> getResourcePacks() {
throw new AssertionError("Not implemented in mixin");
}

/**
* Creates a packet which enables a resource pack for the given properties.
* @return a resource pack send packet
*/
static ResourcePackSendS2CPacket createSendPacket(ServerResourcePackProperties properties) {
return new ResourcePackSendS2CPacket(
properties.id(),
properties.url(),
properties.hash(),
properties.isRequired(),
properties.prompt()
);
}

/**
* Creates a packet which removes a resource pack for the given properties.
* @param uuid the uuid of the resource pack to be removed
* @return a resource pack remove packet
*/
static ResourcePackRemoveS2CPacket createRemovePacket(UUID uuid) {
return new ResourcePackRemoveS2CPacket(Optional.of(uuid));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package net.mcbrawls.packmanager.mixin;

import net.mcbrawls.packmanager.ResourcePackEnvironment;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.MinecraftServer.ServerResourcePackProperties;
import net.minecraft.server.PlayerManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

/**
* Transforms MinecraftServer into a resource pack environment.
*/
@Mixin(MinecraftServer.class)
public class MinecraftServerMixin implements ResourcePackEnvironment {
@Shadow private PlayerManager playerManager;

/**
* The active resource packs on the server.
*/
@Unique
private final Map<UUID, ServerResourcePackProperties> resourcePacks = new HashMap<>();

@Unique
@Override
public void addResourcePack(ServerResourcePackProperties properties) {
// try add resource pack
if (resourcePacks.put(properties.id(), properties) == null) {
// send pack to players if accepted
if (this.playerManager != null) {
var packet = ResourcePackEnvironment.createSendPacket(properties);
this.playerManager.sendToAll(packet);
}
}
}

@Unique
@Override
public void removeResourcePack(UUID uuid) {
// try remove resource pack
if (resourcePacks.remove(uuid) != null) {
// send pack removal to players if accepted
if (this.playerManager != null) {
var packet = ResourcePackEnvironment.createRemovePacket(uuid);
this.playerManager.sendToAll(packet);
}
}
}

@Override
public Set<ServerResourcePackProperties> getResourcePacks() {
return new HashSet<>(resourcePacks.values());
}
}
50 changes: 50 additions & 0 deletions src/main/java/net/mcbrawls/packmanager/mixin/ServerWorldMixin.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,59 @@
package net.mcbrawls.packmanager.mixin;

import net.mcbrawls.packmanager.ResourcePackEnvironment;
import net.minecraft.server.MinecraftServer.ServerResourcePackProperties;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

/**
* Transforms ServerWorld into a resource pack environment.
*/
@Mixin(ServerWorld.class)
public class ServerWorldMixin implements ResourcePackEnvironment {
@Shadow @Final
List<ServerPlayerEntity> players;

/**
* The active resource packs on the world.
*/
@Unique
private final Map<UUID, ServerResourcePackProperties> resourcePacks = new HashMap<>();

@Unique
@Override
public void addResourcePack(ServerResourcePackProperties properties) {
// try add resource pack
if (resourcePacks.put(properties.id(), properties) == null) {
// send pack to players if accepted
var packet = ResourcePackEnvironment.createSendPacket(properties);
this.players.forEach(player -> player.networkHandler.sendPacket(packet));
}
}

@Unique
@Override
public void removeResourcePack(UUID uuid) {
// try remove resource pack
if (resourcePacks.remove(uuid) != null) {
// send pack removal to players if accepted
var packet = ResourcePackEnvironment.createRemovePacket(uuid);
this.players.forEach(player -> player.networkHandler.sendPacket(packet));
}
}

@Override
public Set<ServerResourcePackProperties> getResourcePacks() {
return new HashSet<>(resourcePacks.values());
}
}
105 changes: 105 additions & 0 deletions src/main/kotlin/net/mcbrawls/packmanager/PackManager.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package net.mcbrawls.packmanager

import net.fabricmc.api.DedicatedServerModInitializer
import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents
import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents
import net.minecraft.server.network.SendResourcePackTask
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.server.world.ServerWorld
import org.slf4j.LoggerFactory

object PackManager : DedicatedServerModInitializer {
Expand All @@ -11,5 +18,103 @@ object PackManager : DedicatedServerModInitializer {

override fun onInitializeServer() {
logger.info("Initializing $MOD_NAME")

registerEvents()
}

private fun registerEvents() {
// register configuration event
ServerConfigurationConnectionEvents.CONFIGURE.register { handler, server ->
if (server is ResourcePackEnvironment) {
// send all server pack tasks
val packs = server.resourcePacks
packs.forEach { properties ->
val task = SendResourcePackTask(properties)
handler.addTask(task)
}
}
}

// register join event
ServerPlayConnectionEvents.JOIN.register { handler, sender, server ->
val player = handler.player

// compile pack set
val packs = buildSet {
val world = player.world
if (world is ResourcePackEnvironment) {
addAll(world.resourcePacks)
}

// server resource packs applied at configuration phase
if (server is ResourcePackEnvironment) {
subtract(server.resourcePacks)
}
}

// send all packs
packs.forEach { properties ->
val packet = ResourcePackEnvironment.createSendPacket(properties)
handler.sendPacket(packet)
}
}

// register change world event
ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register { player, origin, destination ->
onWorldChange(player, origin, destination)
}

// register respawn event
ServerPlayerEvents.AFTER_RESPAWN.register { oldPlayer, newPlayer, _ ->
val origin = oldPlayer.serverWorld
val destination = newPlayer.serverWorld
if (origin != destination) {
onWorldChange(newPlayer, origin, destination)
}
}
}

/**
* A procedure called on any world change.
*/
private fun onWorldChange(player: ServerPlayerEntity, origin: ServerWorld, destination: ServerWorld) {
// always true, just check for compiler
if (origin is ResourcePackEnvironment && destination is ResourcePackEnvironment) {
val originPacks = origin.resourcePacks
val destinationPacks = destination.resourcePacks
val server = player.server

// remove old packs
val packsToRemove = buildSet {
addAll(originPacks)
subtract(destinationPacks)

// server resource packs do not need to be modified here
if (server is ResourcePackEnvironment) {
subtract(server.resourcePacks)
}
}

packsToRemove.forEach { properties ->
val packet = ResourcePackEnvironment.createRemovePacket(properties.id)
player.networkHandler.sendPacket(packet)
}

// add new packs
val packsToAdd = buildSet {
addAll(destinationPacks)
subtract(originPacks)

// server resource packs do not need to be modified here
if (server is ResourcePackEnvironment) {
subtract(server.resourcePacks)
}
}

packsToAdd.forEach { properties ->
val packet = ResourcePackEnvironment.createSendPacket(properties)
player.networkHandler.sendPacket(packet)
}
}
}
}

This file was deleted.

5 changes: 3 additions & 2 deletions src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"license": "MIT",
"icon": "assets/packmanager/icon.png",
"environment": "*",
"environment": "server",
"entrypoints": {
"server": [
{
Expand All @@ -29,7 +29,8 @@
"accessWidener": "packmanager.accesswidener",
"custom": {
"loom:injected_interfaces": {
"net/minecraft/server/world/ServerWorld": [ "net/mcbrawls/packmanager/ResourcePackEnvironment" ]
"net/minecraft/server/world/ServerWorld": [ "net/mcbrawls/packmanager/ResourcePackEnvironment" ],
"net/minecraft/server/MinecraftServer": [ "net/mcbrawls/packmanager/ResourcePackEnvironment" ]
}
},
"depends": {
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/packmanager.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"package": "net.mcbrawls.packmanager.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
"MinecraftServerMixin",
"ServerWorldMixin"
],
"injectors": {
Expand Down
Loading

0 comments on commit ffdac2b

Please sign in to comment.