Browse Source

programmable help for commands

Kajetan Johannes Hammerle 4 years ago
parent
commit
5eb776135f

+ 2 - 1
.gitignore

@@ -1,4 +1,5 @@
-/run
+/runClient
+/runServer
 /build
 /gradle
 gradle.properties

+ 2 - 2
build.gradle

@@ -20,14 +20,14 @@ minecraft {
 
     runs {
         client {
-            workingDirectory project.file('run')
+            workingDirectory project.file('runClient')
             property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
             property 'forge.logging.console.level', 'info'
             args '--username', 'kajetanjohannes'
         }
 
         server {
-            workingDirectory project.file('run')
+            workingDirectory project.file('runServer')
             property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
             property 'forge.logging.console.level', 'info'
         }

+ 37 - 0
src/main/java/me/km/ObjectRegistry.java

@@ -1,9 +1,13 @@
 package me.km;
 
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
 import me.km.blocks.ModBlocks;
 import me.km.blocks.cookingpot.TileEntityCookingPot;
 import me.km.entities.ModEntities;
 import me.km.items.ModItems;
+import me.km.utils.ReflectionUtils;
+import me.km.world.ModBiomeProvider;
 import me.km.world.WorldManager;
 import net.minecraft.block.Block;
 import net.minecraft.block.Blocks;
@@ -11,6 +15,11 @@ import net.minecraft.entity.EntityType;
 import net.minecraft.item.Item;
 import net.minecraft.item.Items;
 import net.minecraft.tileentity.TileEntityType;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.world.biome.Biome;
+import net.minecraft.world.biome.Biomes;
+import net.minecraft.world.biome.provider.BiomeProviderType;
+import net.minecraft.world.biome.provider.OverworldBiomeProviderSettings;
 import net.minecraftforge.common.ModDimension;
 import net.minecraftforge.event.RegistryEvent;
 import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -97,4 +106,32 @@ public class ObjectRegistry
     {
         e.getRegistry().register(WorldManager.MOD_DIMENSION);
     }
+    
+    public static BiomeProviderType<OverworldBiomeProviderSettings, ModBiomeProvider> DESERT_BIOME_PROVIDER;
+    public static BiomeProviderType<OverworldBiomeProviderSettings, ModBiomeProvider> SNOW_BIOME_PROVIDER;
+    
+    private static BiomeProviderType createBiomeProviderType(Set<Biome> biomes, String name)
+    {
+        BiomeProviderType provider = ReflectionUtils.newBiomeProviderType((OverworldBiomeProviderSettings settings) -> 
+        {
+            return new ModBiomeProvider(biomes, settings);
+        }, OverworldBiomeProviderSettings::new);
+        provider.setRegistryName(new ResourceLocation("km", name));
+        return provider;
+    }
+    
+    @SubscribeEvent
+    public static void onBiomeProviderTypeRegistry(RegistryEvent.Register<BiomeProviderType<?, ?>> e) 
+    {
+        DESERT_BIOME_PROVIDER = createBiomeProviderType(ImmutableSet.of(
+                    Biomes.DESERT, Biomes.DESERT_HILLS, Biomes.BADLANDS, Biomes.BADLANDS_PLATEAU, 
+                    Biomes.DESERT_LAKES, Biomes.ERODED_BADLANDS, Biomes.MODIFIED_BADLANDS_PLATEAU), "desert_layered");
+        SNOW_BIOME_PROVIDER = createBiomeProviderType(ImmutableSet.of(
+                    Biomes.FROZEN_OCEAN, Biomes.FROZEN_RIVER, Biomes.SNOWY_TUNDRA, 
+                    Biomes.SNOWY_MOUNTAINS, Biomes.SNOWY_BEACH, Biomes.SNOWY_TAIGA, 
+                    Biomes.SNOWY_TAIGA_HILLS, Biomes.DEEP_FROZEN_OCEAN, 
+                    Biomes.ICE_SPIKES, Biomes.SNOWY_TAIGA_MOUNTAINS), "snow_layered");
+        
+        e.getRegistry().registerAll(DESERT_BIOME_PROVIDER, SNOW_BIOME_PROVIDER);
+    }
 }

+ 1 - 6
src/main/java/me/km/Server.java

@@ -140,7 +140,7 @@ public class Server
         }
         MinecraftFunctions.registerFunctions(
                 scripts.getScriptManager(), scripts, perms, scheduler, server, playerBank, 
-                customEventCaller, scriptBank, databank, blockProtection, plotMap);
+                customEventCaller, scriptBank, databank, blockProtection, plotMap, commands);
         
         MinecraftForge.EVENT_BUS.register(new WorldEvents());
         scripts.startScript("startscript");
@@ -154,11 +154,6 @@ public class Server
         databank.closeDataBankConnection();
     }
     
-    public static void executeCommand(String s)
-    {
-        commands.handleCommand(server.getCommandSource(), s);
-    }
-    
     public static ISnuviLogger getLogger()
     {
         return logger;

+ 30 - 15
src/main/java/me/km/permissions/ModCommandManager.java

@@ -31,6 +31,8 @@ public class ModCommandManager extends Commands
     private final PermissionManager perms;
     private final ScriptEvents events;
     private final Scripts scripts;
+    
+    private final ArrayList<CommandNode> customNodes = new ArrayList<>();
 
     public ModCommandManager(boolean isDedicatedServer, PermissionManager perms, ScriptEvents events, Scripts scripts, ISnuviScheduler scheduler)
     {
@@ -54,6 +56,16 @@ public class ModCommandManager extends Commands
         this.scripts = scripts;
     }
     
+    public void clearCustomNodes()
+    {
+        customNodes.clear();
+    }
+    
+    public void addCustomNodes(CommandNode node)
+    {
+        customNodes.add(node);
+    }
+    
     public void registerCommand(Command command)
     {
         commands.put(command.getName(), command);
@@ -181,7 +193,6 @@ public class ModCommandManager extends Commands
                         return 0;
                     }
                 }
-                System.out.println("execute: " + rawCommand + " " + cs.hasPermissionLevel(4));
                 return super.handleCommand(cs, rawCommand);
             }
             events.onMissingPermission(getSource(cs), commandName);
@@ -199,26 +210,30 @@ public class ModCommandManager extends Commands
         RootCommandNode<ISuggestionProvider> rootcommandnode = new RootCommandNode<>();
         map.put(getDispatcher().getRoot(), rootcommandnode);
         this.commandSourceNodesToSuggestionNodes(true, getDispatcher().getRoot(), rootcommandnode, player.getCommandSource(), map);
+        
+        for(CommandNode node : customNodes)
+        {
+            rootcommandnode.addChild(node);
+        }
+        
         player.connection.sendPacket(new SCommandListPacket(rootcommandnode));
     }
 
-    private void commandSourceNodesToSuggestionNodes(boolean first, CommandNode<CommandSource> node, CommandNode<ISuggestionProvider> suggestion, CommandSource source, Map<CommandNode<CommandSource>, CommandNode<ISuggestionProvider>> commandNodeToSuggestionNode)
+    private void commandSourceNodesToSuggestionNodes(boolean first, 
+            CommandNode<CommandSource> node, 
+            CommandNode<ISuggestionProvider> suggestion, 
+            CommandSource source, 
+            Map<CommandNode<CommandSource>, CommandNode<ISuggestionProvider>> map)
     {
         for(CommandNode<CommandSource> commandnode : node.getChildren())
         {
             if((first && perms.hasPermission(source, commandnode.getName()) || (!first && commandnode.canUse(source))))
             {
                 ArgumentBuilder<ISuggestionProvider, ?> argumentbuilder = (ArgumentBuilder) commandnode.createBuilder();
-                argumentbuilder.requires((p_197060_0_) ->
-                {
-                    return true;
-                });
+                argumentbuilder.requires(a -> true);
                 if(argumentbuilder.getCommand() != null)
                 {
-                    argumentbuilder.executes((p_197053_0_) ->
-                    {
-                        return 0;
-                    });
+                    argumentbuilder.executes(a -> 0);
                 }
 
                 if(argumentbuilder instanceof RequiredArgumentBuilder)
@@ -232,15 +247,15 @@ public class ModCommandManager extends Commands
 
                 if(argumentbuilder.getRedirect() != null)
                 {
-                    argumentbuilder.redirect(commandNodeToSuggestionNode.get(argumentbuilder.getRedirect()));
+                    argumentbuilder.redirect(map.get(argumentbuilder.getRedirect()));
                 }
 
-                CommandNode<ISuggestionProvider> commandnode1 = argumentbuilder.build();
-                commandNodeToSuggestionNode.put(commandnode, commandnode1);
-                suggestion.addChild(commandnode1);
+                CommandNode<ISuggestionProvider> commandNode = argumentbuilder.build();
+                map.put(commandnode, commandNode);
+                suggestion.addChild(commandNode);
                 if(!commandnode.getChildren().isEmpty())
                 {
-                    this.commandSourceNodesToSuggestionNodes(false, commandnode, commandnode1, source, commandNodeToSuggestionNode);
+                    this.commandSourceNodesToSuggestionNodes(false, commandnode, commandNode, source, map);
                 }
             }
         }

+ 156 - 8
src/main/java/me/km/snuviscript/MinecraftFunctions.java

@@ -2,6 +2,16 @@ package me.km.snuviscript;
 
 import com.mojang.authlib.GameProfile;
 import com.mojang.brigadier.StringReader;
+import com.mojang.brigadier.arguments.ArgumentType;
+import com.mojang.brigadier.arguments.BoolArgumentType;
+import com.mojang.brigadier.arguments.DoubleArgumentType;
+import com.mojang.brigadier.arguments.FloatArgumentType;
+import com.mojang.brigadier.arguments.IntegerArgumentType;
+import com.mojang.brigadier.arguments.LongArgumentType;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.ArgumentBuilder;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -46,6 +56,7 @@ import me.km.inventory.CustomContainer;
 import me.km.inventory.ModInventory;
 import me.km.networking.ModPacketHandler;
 import me.km.overrides.ModEntityPlayerMP;
+import me.km.permissions.ModCommandManager;
 import me.km.permissions.PermissionManager;
 import me.km.playerbank.IPlayerBank;
 import me.km.plots.PlotMap.Plot;
@@ -58,8 +69,15 @@ import net.minecraft.block.BlockState;
 import net.minecraft.block.ChestBlock;
 import net.minecraft.block.CropsBlock;
 import net.minecraft.block.DoorBlock;
+import net.minecraft.command.CommandSource;
+import net.minecraft.command.Commands;
 import net.minecraft.command.ICommandSource;
+import net.minecraft.command.arguments.BlockStateArgument;
 import net.minecraft.command.arguments.BlockStateParser;
+import net.minecraft.command.arguments.EnchantmentArgument;
+import net.minecraft.command.arguments.ItemArgument;
+import net.minecraft.command.arguments.ItemInput;
+import net.minecraft.command.arguments.PotionArgument;
 import net.minecraft.entity.AgeableEntity;
 import net.minecraft.entity.EntityType;
 import net.minecraft.entity.LivingEntity;
@@ -153,11 +171,135 @@ public class MinecraftFunctions
             PermissionManager perms, SnuviScheduler scheduler, MinecraftServer server, 
             IPlayerBank playerBank, CustomEventCaller cec,
             IScriptBank scriptBank, DataBank dataBank, IBlockProtection blockProtection,
-            WorldPlotMap plots)
+            WorldPlotMap plots, ModCommandManager commands)
     {
         // ---------------------------------------------------------------------
         // Command-library  
         // ---------------------------------------------------------------------
+        sm.registerFunction("command.newhelp", (sc, in) -> Commands.literal(in[0].getString(sc)).requires(p -> perms.hasPermission(p, in[1].getString(sc)))); 
+        sm.registerFunction("command.newhelpliteral", (sc, in) -> 
+        {
+            LiteralArgumentBuilder<CommandSource> arg = Commands.literal(in[0].getString(sc));
+            if(in.length >= 2)
+            {
+                arg.requires(p -> perms.hasPermission(p, in[1].getString(sc)));
+            }
+            return arg;
+        }); 
+        sm.registerFunction("command.newhelpbool", (sc, in) -> 
+        {
+            RequiredArgumentBuilder<CommandSource, Boolean> arg = Commands.argument(in[0].getString(sc), BoolArgumentType.bool());
+            if(in.length >= 2)
+            {
+                arg.requires(p -> perms.hasPermission(p, in[1].getString(sc)));
+            }
+            return arg;
+        }); 
+        sm.registerFunction("command.newhelpdouble", (sc, in) -> 
+        {
+            double min = in[1].getDouble(sc);
+            double max = in[2].getDouble(sc);
+            RequiredArgumentBuilder<CommandSource, Double> arg = Commands.argument(in[0].getString(sc), DoubleArgumentType.doubleArg(min, max));
+            if(in.length >= 4)
+            {
+                arg.requires(p -> perms.hasPermission(p, in[3].getString(sc)));
+            }
+            return arg;
+        }); 
+        sm.registerFunction("command.newhelpfloat", (sc, in) -> 
+        {
+            float min = in[1].getFloat(sc);
+            float max = in[2].getFloat(sc);
+            RequiredArgumentBuilder<CommandSource, Float> arg = Commands.argument(in[0].getString(sc), FloatArgumentType.floatArg(min, max));
+            if(in.length >= 4)
+            {
+                arg.requires(p -> perms.hasPermission(p, in[3].getString(sc)));
+            }
+            return arg;
+        }); 
+        sm.registerFunction("command.newhelpint", (sc, in) -> 
+        {
+            int min = in[1].getInt(sc);
+            int max = in[2].getInt(sc);
+            RequiredArgumentBuilder<CommandSource, Integer> arg = Commands.argument(in[0].getString(sc), IntegerArgumentType.integer(min, max));
+            if(in.length >= 4)
+            {
+                arg.requires(p -> perms.hasPermission(p, in[3].getString(sc)));
+            }
+            return arg;
+        }); 
+        sm.registerFunction("command.newhelplong", (sc, in) -> 
+        {
+            long min = in[1].getLong(sc);
+            long max = in[2].getLong(sc);
+            RequiredArgumentBuilder<CommandSource, Long> arg = Commands.argument(in[0].getString(sc), LongArgumentType.longArg(min, max));
+            if(in.length >= 4)
+            {
+                arg.requires(p -> perms.hasPermission(p, in[3].getString(sc)));
+            }
+            return arg;
+        }); 
+        sm.registerFunction("command.newhelpstring", (sc, in) -> 
+        {
+            RequiredArgumentBuilder<CommandSource, String> arg;
+            if(in[1].getBoolean(sc))
+            {
+                arg = Commands.argument(in[0].getString(sc), StringArgumentType.greedyString());
+            }
+            else
+            {
+                arg = Commands.argument(in[0].getString(sc), StringArgumentType.string());
+            }
+            if(in.length >= 3)
+            {
+                arg.requires(p -> perms.hasPermission(p, in[2].getString(sc)));
+            }
+            return arg;
+        }); 
+        sm.registerFunction("command.newhelpspecial", (sc, in) -> 
+        {
+            RequiredArgumentBuilder<CommandSource, ArgumentType> arg = null;
+            String name = in[0].getString(sc);
+            switch(name)
+            {
+                case "Item": arg = Commands.argument(in[1].getString(sc), (ArgumentType) ItemArgument.item()); break;
+                case "Block": arg = Commands.argument(in[1].getString(sc), (ArgumentType) BlockStateArgument.blockState()); break;
+                case "Potion": arg = Commands.argument(in[1].getString(sc), (ArgumentType) PotionArgument.mobEffect()); break;
+                case "Enchantment": arg = Commands.argument(in[1].getString(sc), (ArgumentType) EnchantmentArgument.enchantment()); break;
+                default:
+                    throw new IllegalArgumentException(String.format("'%s' is not a valid special help", name));
+            }
+            if(in.length >= 3)
+            {
+                arg.requires(p -> perms.hasPermission(p, in[2].getString(sc)));
+            }
+            return arg;
+        }); 
+        sm.registerFunction("command.sendhelp", (sc, in) -> 
+        {
+            server.getPlayerList().getPlayers().forEach(p -> commands.send(p));
+            return Void.TYPE;
+        }); 
+        sm.registerFunction("command.addhelpalias", (sc, in) -> 
+        {
+            ((ArgumentBuilder) in[0].get(sc)).redirect(((ArgumentBuilder) in[1].get(sc)).build());
+            return Void.TYPE;
+        }); 
+        sm.registerFunction("command.addhelpchild", (sc, in) -> 
+        {
+            ((ArgumentBuilder) in[0].get(sc)).then(((ArgumentBuilder) in[1].get(sc)).build());
+            return Void.TYPE;
+        }); 
+        sm.registerFunction("command.addhelp", (sc, in) -> 
+        {
+            commands.addCustomNodes(((LiteralArgumentBuilder<CommandSource>) in[0].get(sc)).build());
+            return Void.TYPE;
+        }); 
+        sm.registerFunction("command.clearhelp", (sc, in) -> 
+        {
+            commands.clearCustomNodes();
+            return Void.TYPE;
+        }); 
         sm.registerFunction("command.add", (sc, in) -> 
         {
             scripts.registerScriptCommand(in[0].getString(sc));
@@ -261,8 +403,6 @@ public class MinecraftFunctions
             stack.setCount(InventoryUtils.addToInventory(((PlayerEntity) in[0].get(sc)).inventory, stack));
             return stack;
         });
-        sm.registerFunction("player.shootprojectile", (sc, in) -> launchProjectile((PlayerEntity) in[0].get(sc), 
-                getClass(in[1].getString(sc)), in[2].getDouble(sc), in.length >= 4 ? in[3].get(sc) : null));
         sm.registerFunction("player.respawn", (sc, in) -> 
         {
             final ServerPlayerEntity p = ((ServerPlayerEntity) in[0].get(sc));
@@ -1146,9 +1286,9 @@ public class MinecraftFunctions
         sm.registerFunction("damage.isabsolute", (sc, in) -> ((DamageSource) in[0].get(sc)).isDamageAbsolute()); 
         sm.registerFunction("damage.isdifficultyscaled", (sc, in) -> ((DamageSource) in[0].get(sc)).isDifficultyScaled()); 
         sm.registerFunction("damage.isexplosion", (sc, in) -> ((DamageSource) in[0].get(sc)).isExplosion()); 
-        sm.registerFunction("damage.isfireDamage", (sc, in) -> ((DamageSource) in[0].get(sc)).isFireDamage()); 
-        sm.registerFunction("damage.isunblockable", (sc, in) -> ((DamageSource) in[0].get(sc)).isMagicDamage()); 
-        sm.registerFunction("damage.ismagic", (sc, in) -> ((DamageSource) in[0].get(sc)).isProjectile()); 
+        sm.registerFunction("damage.isfire", (sc, in) -> ((DamageSource) in[0].get(sc)).isFireDamage()); 
+        sm.registerFunction("damage.ismagic", (sc, in) -> ((DamageSource) in[0].get(sc)).isMagicDamage()); 
+        sm.registerFunction("damage.isprojectile", (sc, in) -> ((DamageSource) in[0].get(sc)).isProjectile()); 
         sm.registerFunction("damage.isunblockable", (sc, in) -> ((DamageSource) in[0].get(sc)).isUnblockable()); 
         sm.registerFunction("damage.gettype", (sc, in) -> ((DamageSource) in[0].get(sc)).getDamageType()); 
         sm.registerFunction("damage.get", (sc, in) -> 
@@ -1230,6 +1370,14 @@ public class MinecraftFunctions
         // ---------------------------------------------------------------------    
         // entity commands
         // ---------------------------------------------------------------------  
+        sm.registerFunction("entity.setnopickup", (sc, in) -> 
+        {
+            ((AbstractArrowEntity) in[0].get(sc)).pickupStatus = AbstractArrowEntity.PickupStatus.DISALLOWED;
+            return Void.TYPE;
+        }); 
+        sm.registerFunction("entity.shootprojectile", (sc, in) -> launchProjectile((LivingEntity) in[0].get(sc), 
+                getClass(in[1].getString(sc)), in[2].getDouble(sc), in.length >= 4 ? in[3].get(sc) : null));
+        sm.registerFunction("entity.isblocking", (sc, in) -> ((LivingEntity) in[0].get(sc)).isActiveItemStackBlocking());
         sm.registerFunction("entity.getarmorthoughness", (sc, in) -> ((LivingEntity) in[0].get(sc)).getAttribute(SharedMonsterAttributes.ARMOR_TOUGHNESS).getValue());
         sm.registerFunction("entity.getarmor", (sc, in) -> (double) ((LivingEntity) in[0].get(sc)).getTotalArmorValue()); 
         sm.registerFunction("entity.getmagicarmor", (sc, in) -> 
@@ -2508,7 +2656,7 @@ public class MinecraftFunctions
         sm.registerFunction("command", (sc, in) -> 
         { 
             final String s = SnuviUtils.connect(sc, in, 0);
-            scheduler.scheduleTask(() -> Server.executeCommand(s)); 
+            scheduler.scheduleTask(() -> commands.handleCommand(server.getCommandSource(), s)); 
             return Void.TYPE;
         });
         sm.registerFunction("isplayer", (sc, in) -> 
@@ -2638,7 +2786,7 @@ public class MinecraftFunctions
         return text;
     }
     
-    private static <T> T launchProjectile(PlayerEntity p, Class<? extends T> projectile, double scale, Object data)
+    private static <T> T launchProjectile(LivingEntity p, Class<? extends T> projectile, double scale, Object data)
     {
         World w = p.world;
         Entity launch = null;

+ 8 - 2
src/main/java/me/km/snuviscript/ScriptEvents.java

@@ -77,11 +77,17 @@ public class ScriptEvents
         {
             scripts.getScriptManager().callEvent(event, sc -> 
             {
-                before.accept(sc);
+                if(before != null)
+                {
+                    before.accept(sc);
+                }
                 sc.setVar("cancel", e.isCanceled());
             }, sc -> 
             {
-                after.accept(sc);
+                if(after != null)
+                {
+                    after.accept(sc);
+                }
                 handleVar(sc, event, "cancel", v -> e.setCanceled(v.getBoolean(sc)));
             });
         }

+ 2 - 17
src/main/java/me/km/utils/ClientReflectionUtils.java

@@ -10,10 +10,8 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.overlay.BossOverlayGui;
 import net.minecraft.client.renderer.entity.EntityRenderer;
 import net.minecraft.client.renderer.entity.EntityRendererManager;
-import net.minecraft.client.renderer.entity.LivingRenderer;
 import net.minecraft.client.renderer.entity.PlayerRenderer;
 import net.minecraft.entity.Entity;
-import net.minecraft.entity.LivingEntity;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.api.distmarker.OnlyIn;
 import org.apache.logging.log4j.LogManager;
@@ -22,8 +20,7 @@ import org.apache.logging.log4j.LogManager;
 public class ClientReflectionUtils
 {
     private final static Method CAN_RENDER_NAME = getMethod(EntityRenderer.class, "func_177070_b", Entity.class);
-    private final static Method RENDER_ENTITY_NAME = getMethod(EntityRenderer.class, "func_188296_a", Entity.class, double.class, double.class, double.class, String.class, double.class);
-    
+
     public static boolean canRenderName(EntityRenderer lr, Entity liv)
     {
         try
@@ -36,19 +33,7 @@ public class ClientReflectionUtils
             return false;
         }
     }
-    
-    public static void renderEntityName(LivingRenderer lr, LivingEntity liv, double x, double y, double z, String name, double distanceSq)
-    {
-        try
-        {
-            RENDER_ENTITY_NAME.invoke(lr, liv, x, y, z, name, distanceSq);
-        }
-        catch(Exception ex)
-        {
-            LogManager.getLogger().warn("renderEntityName - " + ex);
-        }
-    }
-    
+
     private final static Field BOSS_BAR_MAP = getField(BossOverlayGui.class, "field_184060_g");
 
     public static boolean isRenderingBossBar()

+ 2 - 0
src/main/java/me/km/utils/Mapper.java

@@ -85,6 +85,8 @@ public class Mapper
             case "maxCommandChainLength": return GameRules.MAX_COMMAND_CHAIN_LENGTH;
             case "announceAdvancements": return GameRules.ANNOUNCE_ADVANCEMENTS;
             case "disableRaids": return GameRules.DISABLE_RAIDS;
+            case "doInsomnia": return GameRules.DO_INSOMNIA;
+            case "doImmediateRespawn": return GameRules.DO_IMMEDIATE_RESPAWN;
         }
         return null;
     }

+ 21 - 2
src/main/java/me/km/utils/ReflectionUtils.java

@@ -1,25 +1,28 @@
 package me.km.utils;
 
 import cpw.mods.modlauncher.api.INameMappingService;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Map;
+import java.util.function.Function;
 import net.minecraft.command.Commands;
 import net.minecraft.entity.Entity;
-import net.minecraft.entity.LivingEntity;
 import net.minecraft.entity.item.ItemEntity;
 import net.minecraft.entity.player.PlayerAbilities;
 import net.minecraft.entity.player.ServerPlayerEntity;
 import net.minecraft.server.MinecraftServer;
 import net.minecraft.server.management.PlayerList;
-import net.minecraft.util.DamageSource;
 import net.minecraft.util.FoodStats;
 import net.minecraft.util.ResourceLocation;
 import net.minecraft.world.Explosion;
 import net.minecraft.world.GameRules;
 import net.minecraft.world.IWorld;
 import net.minecraft.world.World;
+import net.minecraft.world.biome.provider.BiomeProvider;
+import net.minecraft.world.biome.provider.BiomeProviderType;
+import net.minecraft.world.biome.provider.IBiomeProviderSettings;
 import net.minecraft.world.storage.WorldInfo;
 import net.minecraftforge.common.DimensionManager;
 import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
@@ -305,4 +308,20 @@ public class ReflectionUtils
     {
         setInt(rule, INTEGER_VALUE, value);
     }
+    
+    
+    public static <C extends IBiomeProviderSettings, T extends BiomeProvider> BiomeProviderType 
+        newBiomeProviderType(Function<C, T> factory, Function<WorldInfo, C> settingsFactory)
+    {
+        try
+        {
+            Constructor<BiomeProviderType> con = (Constructor<BiomeProviderType>) BiomeProviderType.class.getDeclaredConstructors()[0];
+            con.setAccessible(true);
+            return con.newInstance(factory, settingsFactory);
+        }
+        catch(Exception ex)
+        {
+            return null;
+        }
+    }
 }

+ 56 - 0
src/main/java/me/km/world/ModBiomeProvider.java

@@ -0,0 +1,56 @@
+package me.km.world;
+
+import java.util.Set;
+import net.minecraft.util.registry.Registry;
+import net.minecraft.world.biome.Biome;
+import net.minecraft.world.biome.provider.BiomeProvider;
+import net.minecraft.world.biome.provider.OverworldBiomeProviderSettings;
+import net.minecraft.world.gen.layer.Layer;
+import net.minecraft.world.gen.layer.LayerUtil;
+
+public class ModBiomeProvider extends BiomeProvider
+{
+    private final Layer genBiomes;
+    private final Biome[] biomeArray;
+
+    public ModBiomeProvider(Set<Biome> biomes, OverworldBiomeProviderSettings settingsProvider)
+    {
+        super(biomes);
+        biomeArray = biomes.toArray(new Biome[biomes.size()]);
+        this.genBiomes = LayerUtil.func_227474_a_(settingsProvider.func_226850_a_(), settingsProvider.func_226851_b_(), settingsProvider.getGeneratorSettings());
+    }
+
+    @Override
+    public Biome getNoiseBiome(int x, int y, int z)
+    {
+        Biome vanillaBiome = genBiomes.func_215738_a(x, z);
+        
+        float min = Float.MAX_VALUE;
+        float min2 = Float.MAX_VALUE;
+        Biome minBiome = null;
+        Biome minBiome2 = null;
+        for(Biome b : biomeArray)
+        {
+            float distance = Math.abs(b.getDepth() - vanillaBiome.getDepth());
+            if(distance < min)
+            {
+                min2 = min;
+                minBiome2 = minBiome;
+                
+                min = distance;
+                minBiome = b;
+            }
+            else if(distance < min2)
+            {
+                min2 = distance;
+                minBiome2 = b;
+            }
+        }
+        
+        if((Registry.BIOME.getId(vanillaBiome) % 2) == 1)
+        {
+            return minBiome;
+        }
+        return minBiome2;
+    }
+}

+ 19 - 3
src/main/java/me/km/world/ModOverworldDimension.java

@@ -2,10 +2,15 @@ package me.km.world;
 
 import me.km.utils.ReflectionUtils;
 import net.minecraft.world.World;
+import net.minecraft.world.biome.provider.BiomeProviderType;
+import net.minecraft.world.biome.provider.OverworldBiomeProviderSettings;
 import net.minecraft.world.dimension.DimensionType;
 import net.minecraft.world.dimension.OverworldDimension;
 import net.minecraft.world.gen.ChunkGenerator;
+import net.minecraft.world.gen.ChunkGeneratorType;
 import net.minecraft.world.gen.GenerationSettings;
+import net.minecraft.world.gen.OverworldChunkGenerator;
+import net.minecraft.world.gen.OverworldGenSettings;
 import org.apache.logging.log4j.LogManager;
 
 public class ModOverworldDimension extends OverworldDimension
@@ -19,14 +24,25 @@ public class ModOverworldDimension extends OverworldDimension
     public ChunkGenerator<? extends GenerationSettings> createChunkGenerator()
     {
         LogManager.getLogger().warn("Try swapping " + world + " " + world.getDimension().getType());
-        
+
         if(world.getDimension().getType().isVanilla())
         {
             LogManager.getLogger().warn("no swap in vanilla world");
             return super.createChunkGenerator();
         }
-        
-        ReflectionUtils.setWorldInfo(world, new ModWorldInfo(world.getWorldInfo(), WorldManager.getName(world), world.getServer()));
+
+        ModWorldInfo info = new ModWorldInfo(world.getWorldInfo(), WorldManager.getName(world), world.getServer());
+        ReflectionUtils.setWorldInfo(world, info);
+
+        ModWorldInfo.Type type = info.getType();
+        if(type != ModWorldInfo.Type.VOID && type != ModWorldInfo.Type.VANILLA)
+        {
+            ChunkGeneratorType<OverworldGenSettings, OverworldChunkGenerator> chunkGenType = ChunkGeneratorType.SURFACE;
+            BiomeProviderType<OverworldBiomeProviderSettings, ModBiomeProvider> provider = info.getType().getProvider();
+            OverworldGenSettings genSettings = chunkGenType.createSettings();
+            OverworldBiomeProviderSettings providerSettings = provider.func_226840_a_(this.world.getWorldInfo()).setGeneratorSettings(genSettings);
+            return chunkGenType.create(this.world, provider.create(providerSettings), genSettings);
+        }
         
         return super.createChunkGenerator();
     }

+ 40 - 6
src/main/java/me/km/world/ModWorldInfo.java

@@ -4,6 +4,7 @@ import net.minecraft.world.Difficulty;
 import net.minecraft.world.storage.DerivedWorldInfo;
 import net.minecraft.world.storage.WorldInfo;
 import me.hammerle.snuviscript.config.SnuviConfig;
+import me.km.ObjectRegistry;
 import me.km.Server;
 import me.km.utils.ReflectionUtils;
 import net.minecraft.nbt.CompoundNBT;
@@ -12,9 +13,26 @@ import net.minecraft.server.MinecraftServer;
 import net.minecraft.world.GameRules;
 import static net.minecraft.world.GameRules.*;
 import net.minecraft.world.WorldType;
+import net.minecraft.world.biome.provider.BiomeProviderType;
+import net.minecraft.world.biome.provider.OverworldBiomeProviderSettings;
 
 public class ModWorldInfo extends DerivedWorldInfo
 {
+    public static enum Type
+    {
+        VANILLA, VOID, DESERT, SNOW;
+        
+        public BiomeProviderType<OverworldBiomeProviderSettings, ModBiomeProvider> getProvider()
+        {
+            switch(this)
+            {
+                case DESERT: return ObjectRegistry.DESERT_BIOME_PROVIDER;
+                case SNOW: return ObjectRegistry.SNOW_BIOME_PROVIDER;
+            }
+            return null;
+        }
+    }
+    
     private final SnuviConfig config;
     
     private long gameTime;
@@ -27,7 +45,7 @@ public class ModWorldInfo extends DerivedWorldInfo
     private Difficulty difficulty;
     private final GameRules gameRules = new GameRules();
     
-    private boolean voidWorld;
+    private Type type;
    
     public ModWorldInfo(WorldInfo info, String name, MinecraftServer server)
     {
@@ -40,7 +58,7 @@ public class ModWorldInfo extends DerivedWorldInfo
         }
         onLoad(info, server);
         
-        org.apache.logging.log4j.LogManager.getLogger().warn("status: " + voidWorld);
+        org.apache.logging.log4j.LogManager.getLogger().warn("status: " + type);
     }
     
     private void onLoad(WorldInfo info, MinecraftServer server)
@@ -95,8 +113,17 @@ public class ModWorldInfo extends DerivedWorldInfo
         ReflectionUtils.setIntegerValue(gameRules.get(MAX_COMMAND_CHAIN_LENGTH), config.getInt("maxCommandChainLength", rules.getInt(MAX_COMMAND_CHAIN_LENGTH)));
         gameRules.get(ANNOUNCE_ADVANCEMENTS).set(config.getBoolean("announceAdvancements", rules.getBoolean(ANNOUNCE_ADVANCEMENTS)), server);
         gameRules.get(DISABLE_RAIDS).set(config.getBoolean("disableRaids", rules.getBoolean(DISABLE_RAIDS)), server);
+        gameRules.get(DO_INSOMNIA).set(config.getBoolean("doInsomnia", rules.getBoolean(DO_INSOMNIA)), server);
+        gameRules.get(DO_IMMEDIATE_RESPAWN).set(config.getBoolean("doImmediateRespawn", rules.getBoolean(DO_IMMEDIATE_RESPAWN)), server);
         
-        voidWorld = config.getBoolean("voidWorld", false);
+        try
+        {
+            type = Type.valueOf(config.getString("type", ""));
+        }
+        catch(IllegalArgumentException ex)
+        {
+            type = Type.VOID;
+        }
     }
     
     public void onSave()
@@ -134,8 +161,10 @@ public class ModWorldInfo extends DerivedWorldInfo
         config.set("maxCommandChainLength", gameRules.getInt(MAX_COMMAND_CHAIN_LENGTH));
         config.set("announceAdvancements", gameRules.getBoolean(ANNOUNCE_ADVANCEMENTS));
         config.set("disableRaids", gameRules.getBoolean(DISABLE_RAIDS));
+        config.set("doInsomnia", gameRules.getBoolean(DO_INSOMNIA));
+        config.set("doImmediateRespawn", gameRules.getBoolean(DO_IMMEDIATE_RESPAWN));
         
-        config.set("voidWorld", voidWorld);
+        config.set("type", type);
         
         config.save();
     }
@@ -245,17 +274,22 @@ public class ModWorldInfo extends DerivedWorldInfo
     @Override
     public WorldType getGenerator()
     {
-        if(voidWorld)
+        if(type == Type.VOID)
         {
             return WorldType.FLAT;
         }
         return super.getGenerator();
     }
+    
+    public Type getType()
+    {
+        return type;
+    }
 
     @Override
     public CompoundNBT getGeneratorOptions()
     {
-        if(voidWorld)
+        if(type == Type.VOID)
         {
             CompoundNBT base = new CompoundNBT();