early low-level command/network APIs

This commit is contained in:
asie 2018-11-08 01:14:35 +01:00
parent b71f41c16f
commit 524f8cfb7f
17 changed files with 424 additions and 12 deletions

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.commands;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.command.ServerCommandSource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
public class CommandRegistry {
public static final CommandRegistry INSTANCE = new CommandRegistry();
private final List<Consumer<CommandDispatcher<ServerCommandSource>>> serverCommands;
private final List<Consumer<CommandDispatcher<ServerCommandSource>>> dedicatedServerCommands;
public CommandRegistry() {
this.serverCommands = new ArrayList<>();
this.dedicatedServerCommands = new ArrayList<>();
}
public List<Consumer<CommandDispatcher<ServerCommandSource>>> entries(boolean dedicated) {
return Collections.unmodifiableList(dedicated ? dedicatedServerCommands : serverCommands);
}
public void register(boolean dedicated, Consumer<CommandDispatcher<ServerCommandSource>> consumer) {
if (dedicated) {
dedicatedServerCommands.add(consumer);
} else {
serverCommands.add(consumer);
}
}
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.commands;
import com.mojang.brigadier.CommandDispatcher;
import net.fabricmc.fabric.commands.CommandRegistry;
import net.minecraft.command.ServerCommandManager;
import net.minecraft.command.ServerCommandSource;
import org.apache.logging.log4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
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.callback.CallbackInfo;
@Mixin(ServerCommandManager.class)
public class MixinServerCommandManager {
@Shadow
private static Logger LOGGER;
@Shadow
private CommandDispatcher<ServerCommandSource> dispatcher;
@Inject(method = "<init>(Z)V", at = @At("RETURN"))
public void addMethods(boolean dedicated, CallbackInfo info) {
// TODO: Run before findAmbiguities
CommandRegistry.INSTANCE.entries(false).forEach((e) -> e.accept(dispatcher));
if (dedicated) {
CommandRegistry.INSTANCE.entries(true).forEach((e) -> e.accept(dispatcher));
}
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.networking;
import net.fabricmc.api.Side;
import net.fabricmc.fabric.networking.CustomPayloadHandlerRegistry;
import net.fabricmc.fabric.networking.PacketContext;
import net.fabricmc.fabric.networking.SPacketCustomPayloadAccessor;
import net.fabricmc.fabric.networking.impl.PacketContextImpl;
import net.minecraft.client.MinecraftGame;
import net.minecraft.client.network.handler.ClientGameNetworkHandler;
import net.minecraft.entity.player.EntityPlayerServer;
import net.minecraft.network.handler.ServerPlayNetworkHandler;
import net.minecraft.network.packet.client.CPacketCustomPayload;
import net.minecraft.network.packet.server.SPacketCustomPayload;
import net.minecraft.server.MinecraftServer;
import org.spongepowered.asm.mixin.Mixin;
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.callback.CallbackInfo;
@Mixin(ClientGameNetworkHandler.class)
public class MixinClientPlayNetworkHandler {
@Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true)
public void onCustomPayload(CPacketCustomPayload packet, CallbackInfo info) {
MinecraftGame game = MinecraftGame.getInstance();
if (CustomPayloadHandlerRegistry.CLIENT.accept(packet.getChannel(), new PacketContextImpl(Side.CLIENT, game.player, game), packet.getData())) {
info.cancel();
}
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.networking;
import net.fabricmc.fabric.networking.SPacketCustomPayloadAccessor;
import net.minecraft.network.packet.server.SPacketCustomPayload;
import net.minecraft.util.Identifier;
import net.minecraft.util.PacketByteBuf;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(SPacketCustomPayload.class)
public class MixinSPacketCustomPayload implements SPacketCustomPayloadAccessor {
@Shadow
private Identifier channel;
@Shadow
private PacketByteBuf data;
@Override
public Identifier getChannel() {
return channel;
}
@Override
public PacketByteBuf getData() {
return data;
}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.networking;
import net.fabricmc.api.Side;
import net.fabricmc.fabric.networking.CustomPayloadHandlerRegistry;
import net.fabricmc.fabric.networking.PacketContext;
import net.fabricmc.fabric.networking.SPacketCustomPayloadAccessor;
import net.fabricmc.fabric.networking.impl.PacketContextImpl;
import net.minecraft.entity.player.EntityPlayerServer;
import net.minecraft.network.handler.ServerPlayNetworkHandler;
import net.minecraft.network.packet.server.SPacketCustomPayload;
import net.minecraft.server.MinecraftServer;
import org.spongepowered.asm.mixin.Mixin;
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.callback.CallbackInfo;
@Mixin(ServerPlayNetworkHandler.class)
public class MixinServerPlayNetworkHandler {
@Shadow
private MinecraftServer server;
@Shadow
private EntityPlayerServer player;
private PacketContext fabricPacketContext;
@Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true)
public void onCustomPayload(SPacketCustomPayload packet, CallbackInfo info) {
if (fabricPacketContext == null || fabricPacketContext.getPlayer() != player) {
fabricPacketContext = new PacketContextImpl(Side.SERVER, player, server);
}
SPacketCustomPayloadAccessor accessor = ((SPacketCustomPayloadAccessor) packet);
if (CustomPayloadHandlerRegistry.SERVER.accept(accessor.getChannel(), fabricPacketContext, accessor.getData())) {
info.cancel();
}
}
}

View file

@ -20,6 +20,7 @@ import net.fabricmc.fabric.resources.ModResourcePackUtil;
import net.minecraft.client.MinecraftGame;
import net.minecraft.resource.ReloadableResourceManager;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@ -36,6 +37,6 @@ public class MixinMinecraftGame {
@Inject(method = "reloadResources()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ReloadableResourceManager;reload(Ljava/util/List;)V", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD)
public void reloadResources(CallbackInfo info, List<ResourcePack> list) {
ModResourcePackUtil.appendModResourcePacks(list);
ModResourcePackUtil.appendModResourcePacks(list, ResourceType.ASSETS);
}
}

View file

@ -20,6 +20,7 @@ import net.fabricmc.fabric.resources.ModResourcePackUtil;
import net.minecraft.client.MinecraftGame;
import net.minecraft.resource.ReloadableResourceManager;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.LevelProperties;
import org.spongepowered.asm.mixin.Mixin;
@ -36,8 +37,8 @@ public class MixinMinecraftServer {
@Shadow
private ReloadableResourceManager dataManager;
@Inject(method = "method_3752", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ReloadableResourceManager;reload(Ljava/util/List;)V", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD)
public void method_3752(LevelProperties properties, CallbackInfo info, List<ResourcePack> list) {
ModResourcePackUtil.appendModResourcePacks(list);
@Inject(method = "reloadDataPacks", at = @At(value = "INVOKE", target = "Lnet/minecraft/resource/ReloadableResourceManager;reload(Ljava/util/List;)V", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD)
public void reloadDataPacks(LevelProperties properties, CallbackInfo info, List<ResourcePack> list) {
ModResourcePackUtil.appendModResourcePacks(list, ResourceType.DATA);
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.networking;
import net.minecraft.util.Identifier;
import net.minecraft.util.PacketByteBuf;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
public class CustomPayloadHandlerRegistry {
public static final CustomPayloadHandlerRegistry CLIENT = new CustomPayloadHandlerRegistry();
public static final CustomPayloadHandlerRegistry SERVER = new CustomPayloadHandlerRegistry();
protected final Map<Identifier, BiConsumer<PacketContext, PacketByteBuf>> consumerMap;
protected CustomPayloadHandlerRegistry() {
consumerMap = new HashMap<>();
}
public void register(Identifier id, BiConsumer<PacketContext, PacketByteBuf> consumer) {
if (consumerMap.containsKey(id)) {
// TODO: log warning
}
consumerMap.put(id, consumer);
}
public boolean accept(Identifier identifier, PacketContext context, PacketByteBuf buf) {
BiConsumer<PacketContext, PacketByteBuf> consumer = consumerMap.get(context);
if (consumer != null) {
consumer.accept(context, buf);
return true;
} else {
return false;
}
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.networking;
import net.fabricmc.api.Side;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ThreadTaskQueue;
/**
* Interface defining a context used during packet processing. Allows access
* to additional information, such as the source/target of the player, or
* the correct task queue to enqueue synchronization-requiring code on.
*/
public interface PacketContext {
Side getSide();
EntityPlayer getPlayer();
ThreadTaskQueue getTaskQueue();
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.networking;
import net.minecraft.util.Identifier;
import net.minecraft.util.PacketByteBuf;
/**
* Helper interface containing getters for SPacketCustomPayload
* which were omitted from the compiled game.
*/
public interface SPacketCustomPayloadAccessor {
Identifier getChannel();
PacketByteBuf getData();
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2016, 2017, 2018 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.networking.impl;
import net.fabricmc.api.Side;
import net.fabricmc.fabric.networking.PacketContext;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ThreadTaskQueue;
public class PacketContextImpl implements PacketContext {
private final Side side;
private final EntityPlayer player;
private final ThreadTaskQueue taskQueue;
public PacketContextImpl(Side side, EntityPlayer player, ThreadTaskQueue taskQueue) {
this.side = side;
this.player = player;
this.taskQueue = taskQueue;
}
@Override
public Side getSide() {
return side;
}
@Override
public EntityPlayer getPlayer() {
return player;
}
@Override
public ThreadTaskQueue getTaskQueue() {
return taskQueue;
}
}

View file

@ -17,8 +17,8 @@
package net.fabricmc.fabric.resources;
import net.fabricmc.loader.ModInfo;
import net.minecraft.class_3266;
import net.minecraft.resource.DirectoryResourcePack;
import net.minecraft.resource.ResourceNotFoundException;
import java.io.*;
@ -42,7 +42,7 @@ public class ModDirectoryResourcePack extends DirectoryResourcePack {
} catch (FileNotFoundException e) {
InputStream stream = ModResourcePackUtil.openDefault(info, filename);
if (stream == null) {
throw new class_3266(this.base, filename);
throw new ResourceNotFoundException(this.base, filename);
}
return stream;
}

View file

@ -21,6 +21,7 @@ import net.fabricmc.loader.FabricLoader;
import net.fabricmc.loader.ModContainer;
import net.fabricmc.loader.ModInfo;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import org.apache.commons.io.IOUtils;
import java.io.File;
@ -28,6 +29,9 @@ import java.io.InputStream;
import java.util.List;
import java.util.Locale;
/**
* Internal utilities for managing resource packs.
*/
public final class ModResourcePackUtil {
public static final int PACK_FORMAT_VERSION = 4;
@ -35,7 +39,7 @@ public final class ModResourcePackUtil {
}
public static void appendModResourcePacks(List<ResourcePack> packList) {
public static void appendModResourcePacks(List<ResourcePack> packList, ResourceType type) {
for (ModContainer container : FabricLoader.INSTANCE.getMods()) {
File file = container.getOriginFile();
if (file.isDirectory()) {
@ -50,12 +54,12 @@ public final class ModResourcePackUtil {
}
public static boolean containsDefault(ModInfo info, String filename) {
return "pack.mcmeta".equals(filename) || "icon.png".equals(filename);
return "pack.mcmeta".equals(filename) || "pack.png".equals(filename);
}
public static InputStream openDefault(ModInfo info, String filename) {
switch (filename) {
case "icon.png":
case "pack.png":
return ModResourcePackUtil.class.getClassLoader().getResourceAsStream("assets/fabric/textures/misc/default_icon.png");
case "pack.mcmeta":
String description = info.getName();

View file

@ -18,7 +18,7 @@ package net.fabricmc.fabric.resources;
import com.google.common.io.ByteStreams;
import net.fabricmc.loader.ModInfo;
import net.minecraft.class_3266;
import net.minecraft.resource.ResourceNotFoundException;
import net.minecraft.resource.ZipResourcePack;
import java.io.File;
@ -46,7 +46,7 @@ public class ModZipResourcePack extends ZipResourcePack {
} catch (FileNotFoundException e) {
InputStream stream = ModResourcePackUtil.openDefault(info, filename);
if (stream == null) {
throw new class_3266(this.base, filename);
throw new ResourceNotFoundException(this.base, filename);
}
return stream;
}

View file

@ -1,7 +1,7 @@
{
"id": "fabric",
"name": "Fabric API",
"version": "0.0.1",
"version": "0.0.2",
"side": "universal",
"initializers": [
],

View file

@ -3,6 +3,7 @@
"package": "net.fabricmc.fabric.mixin",
"compatibilityLevel": "JAVA_8",
"mixins": [
"networking.MixinClientPlayNetworkHandler",
"resources.MixinMinecraftGame"
],
"refmap": "net.fabricmc.fabric.refmap.json",

View file

@ -3,6 +3,9 @@
"package": "net.fabricmc.fabric.mixin",
"compatibilityLevel": "JAVA_8",
"mixins": [
"commands.MixinServerCommandManager",
"networking.MixinServerPlayNetworkHandler",
"networking.MixinSPacketCustomPayload",
"resources.MixinMinecraftServer"
],
"refmap": "net.fabricmc.fabric.refmap.json",