diff --git a/changelog b/changelog index c410ab62a..96cce6458 100644 --- a/changelog +++ b/changelog @@ -1,29 +1,14 @@ ## Added -* A new legendary weapon +* `/ntmserver` + * Functions like `/ntmclient` but for common settings + * Can toggle `DAMAGE_COMPATIBILITY_MODE`, off by default, enables a more compatible (but slightly jankier) version of the bullet damage code + * `MINE__DAMAGE` can be used to adjust landmine damage ## Changed -* Updated russian localization -* Large deposits (hematite, malachite, bauxite) and caves (sulfur, asbestos) can now be toggled in the config -* Removed recipes for most old particle accelerator parts -* Dense coils no longer have recipes either for the most part, all coils with no recipes can be recycled back into dense wires -* Natural gas can now be processed in a pyrolysis oven, 12k of gas yields 8k hydrogen and one graphite ingot -* Saturnite now has an alternate recipe, adding one pile of borax for doubled output -* All mass storage units (except wood) are now substantially cheaper -* Reduced base spread for all 12 and 10 gauge buckshot shells from 0.05 to 0.035 -* Reduced legendary 12 lever action's spread multiplier from x1.35 to x1.15 -* Bullet casings now spawn with randomized angular velocity -* Bullet casings now correctly bounce off walls, and change angles when bouncing -* Two previously unobtainable legendaries are now in the red room loot pool (about 10x less common than most other items) +* Fat mines now use the standardized mini nuke code + * Fat mines now have a base damage of exactly 100, being identical to demolition mini nukes + * Fat mines now gib affected entities +* IV bags now use `setHealth` operations instead of dealing damage, preventing health duplication by just avoiding the damage ## Fixed -* Fixed an issue where `/ntmreload` would load fluids after recipes, meaning that recipes using newly added fluids would not work correctly, as the fluids don't exist by the time the recipe is loaded -* Fixed bedrock coltan being way too common, drowning out almost all other bedrock ores -* Fixed rotary furnace not saving its output stack -* Fixed strand caster water check being incorrect, creating negative water by allowing operations with insufficient cooling -* Fixed radar not using the small remaining amount of power, causing the animation getting stuck -* Fixed the new system structures being way too common -* Fixed RBMKs losing all their flux when reloading the world -* Fixed issue where DODD fuel item stats would only update when the GUI was open -* Fixed muzzle flashes not being fullbright -* Fixed guns having their name permanently visible over the toolbar -* Fixed hangman being absolutely gigantic when dropped \ No newline at end of file +* Fixed animation error on the MAS-36 \ No newline at end of file diff --git a/src/main/java/com/hbm/blocks/bomb/Landmine.java b/src/main/java/com/hbm/blocks/bomb/Landmine.java index 03a505e55..ec75235b6 100644 --- a/src/main/java/com/hbm/blocks/bomb/Landmine.java +++ b/src/main/java/com/hbm/blocks/bomb/Landmine.java @@ -3,8 +3,8 @@ package com.hbm.blocks.bomb; import java.util.Random; import com.hbm.blocks.ModBlocks; +import com.hbm.config.ServerConfig; import com.hbm.explosion.ExplosionLarge; -import com.hbm.explosion.ExplosionNukeSmall; import com.hbm.explosion.vanillant.ExplosionVNT; import com.hbm.explosion.vanillant.standard.BlockAllocatorStandard; import com.hbm.explosion.vanillant.standard.BlockProcessorStandard; @@ -13,8 +13,13 @@ import com.hbm.explosion.vanillant.standard.ExplosionEffectWeapon; import com.hbm.explosion.vanillant.standard.PlayerProcessorStandard; import com.hbm.interfaces.IBomb; import com.hbm.items.ModItems; +import com.hbm.items.weapon.sedna.factory.XFactoryCatapult; +import com.hbm.main.MainRegistry; +import com.hbm.packet.PacketDispatcher; +import com.hbm.packet.toclient.AuxParticlePacketNT; import com.hbm.tileentity.bomb.TileEntityLandmine; +import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint; import net.minecraft.block.Block; import net.minecraft.block.BlockContainer; import net.minecraft.block.BlockFence; @@ -23,6 +28,7 @@ import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.IBlockAccess; @@ -138,7 +144,7 @@ public class Landmine extends BlockContainer implements IBomb { if(this == ModBlocks.mine_ap) { ExplosionVNT vnt = new ExplosionVNT(world, x + 0.5, y + 0.5, z + 0.5, 3F); - vnt.setEntityProcessor(new EntityProcessorCrossSmooth(0.5, 10F).setupPiercing(5F, 0.2F)); + vnt.setEntityProcessor(new EntityProcessorCrossSmooth(0.5, ServerConfig.MINE_AP_DAMAGE.get()).setupPiercing(5F, 0.2F)); vnt.setPlayerProcessor(new PlayerProcessorStandard()); vnt.setSFX(new ExplosionEffectWeapon(5, 1F, 0.5F)); vnt.explode(); @@ -146,13 +152,13 @@ public class Landmine extends BlockContainer implements IBomb { ExplosionVNT vnt = new ExplosionVNT(world, x + 0.5, y + 0.5, z + 0.5, 4F); vnt.setBlockAllocator(new BlockAllocatorStandard()); vnt.setBlockProcessor(new BlockProcessorStandard()); - vnt.setEntityProcessor(new EntityProcessorCrossSmooth(1, 35).setupPiercing(15F, 0.2F)); + vnt.setEntityProcessor(new EntityProcessorCrossSmooth(1, ServerConfig.MINE_HE_DAMAGE.get()).setupPiercing(15F, 0.2F)); vnt.setPlayerProcessor(new PlayerProcessorStandard()); vnt.setSFX(new ExplosionEffectWeapon(15, 3.5F, 1.25F)); vnt.explode(); } else if(this == ModBlocks.mine_shrap) { ExplosionVNT vnt = new ExplosionVNT(world, x + 0.5, y + 0.5, z + 0.5, 3F); - vnt.setEntityProcessor(new EntityProcessorCrossSmooth(0.5, 7.5F)); + vnt.setEntityProcessor(new EntityProcessorCrossSmooth(0.5, ServerConfig.MINE_SHRAP_DAMAGE.get())); vnt.setPlayerProcessor(new PlayerProcessorStandard()); vnt.setSFX(new ExplosionEffectWeapon(5, 1F, 0.5F)); vnt.explode(); @@ -160,7 +166,20 @@ public class Landmine extends BlockContainer implements IBomb { ExplosionLarge.spawnShrapnelShower(world, x + 0.5, y + 0.5, z + 0.5, 0, 1D, 0, 45, 0.2D); ExplosionLarge.spawnShrapnels(world, x + 0.5, y + 0.5, z + 0.5, 5); } else if(this == ModBlocks.mine_fat) { - ExplosionNukeSmall.explode(world, x + 0.5, y + 0.5, z + 0.5, ExplosionNukeSmall.PARAMS_MEDIUM); + + ExplosionVNT vnt = new ExplosionVNT(world, x + 0.5, y + 0.5, z + 0.5, 10); + vnt.setBlockAllocator(new BlockAllocatorStandard(64)); + vnt.setBlockProcessor(new BlockProcessorStandard()); + vnt.setEntityProcessor(new EntityProcessorCrossSmooth(2, ServerConfig.MINE_NUKE_DAMAGE.get()).withRangeMod(1.5F)); + vnt.setPlayerProcessor(new PlayerProcessorStandard()); + vnt.explode(); + + XFactoryCatapult.incrementRad(world, x, y, z, 1.5F); + NBTTagCompound data = new NBTTagCompound(); + data.setString("type", "muke"); + data.setBoolean("balefire", MainRegistry.polaroidID == 11 || world.rand.nextInt(100) == 0); + PacketDispatcher.wrapper.sendToAllAround(new AuxParticlePacketNT(data, x + 0.5, y + 0.5, z + 0.5), new TargetPoint(world.provider.dimensionId, x + 0.5, y + 0.5, z + 0.5, 250)); + } } diff --git a/src/main/java/com/hbm/commands/CommandReloadClient.java b/src/main/java/com/hbm/commands/CommandReloadClient.java index 6f0c9672a..84f21988b 100644 --- a/src/main/java/com/hbm/commands/CommandReloadClient.java +++ b/src/main/java/com/hbm/commands/CommandReloadClient.java @@ -1,24 +1,18 @@ package com.hbm.commands; -import java.util.Collections; -import java.util.List; -import java.util.Map.Entry; -import java.util.stream.Collectors; +import java.util.HashMap; import com.hbm.config.ClientConfig; -import com.hbm.config.ClientConfig.ConfigWrapper; +import com.hbm.config.RunningConfig.ConfigWrapper; import cpw.mods.fml.relauncher.FMLLaunchHandler; import cpw.mods.fml.relauncher.Side; -import net.minecraft.command.CommandBase; -import net.minecraft.command.CommandException; import net.minecraft.command.ICommandSender; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; import net.minecraftforge.client.ClientCommandHandler; -public class CommandReloadClient extends CommandBase { +public class CommandReloadClient extends CommandReloadConfig { public static void register() { if(FMLLaunchHandler.side() != Side.CLIENT) return; @@ -34,95 +28,26 @@ public class CommandReloadClient extends CommandBase { public String getCommandUsage(ICommandSender sender) { return "/ntmclient help"; } - - @Override - public boolean canCommandSenderUseCommand(ICommandSender sender) { - return sender instanceof EntityPlayer; - } - - @Override - public void processCommand(ICommandSender sender, String[] args) { - - if(args.length < 1) throw new CommandException(getCommandUsage(sender)); - - String operator = args[0]; - - if("help".equals(operator)) { - - if(args.length >= 2) { - String command = args[1]; - if("help".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Shows usage for /ntmclient subcommands.")); - if("list".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Shows all client variable names and values.")); - if("reload".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Reads client variables from the config file.")); - if("get".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Shows value for the specified variable name.")); - if("set".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Sets a variable's value and saves it to the config file.")); - } else { - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmclient " + EnumChatFormatting.GOLD + "help " + EnumChatFormatting.RED + "")); - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmclient " + EnumChatFormatting.GOLD + "list")); - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmclient " + EnumChatFormatting.GOLD + "reload")); - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmclient " + EnumChatFormatting.GOLD + "get " + EnumChatFormatting.RED + "")); - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmclient " + EnumChatFormatting.GOLD + "set " + EnumChatFormatting.RED + " ")); - } - return; - } - - if("list".equals(operator)) { - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "CLIENT VARIABLES:")); - for(Entry line : ClientConfig.configMap.entrySet()) { - sender.addChatMessage(new ChatComponentText(" " + EnumChatFormatting.GOLD + line.getKey() + ": " + EnumChatFormatting.YELLOW + line.getValue().value)); - } - return; - } - - if("reload".equals(operator)) { - ClientConfig.reload(); - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Variables loaded from config file.")); - return; - } - - if(args.length < 2) throw new CommandException(getCommandUsage(sender)); - - String key = args[1]; - - if("get".equals(operator)) { - ConfigWrapper wrapper = ClientConfig.configMap.get(key); - if(wrapper == null) throw new CommandException("Key does not exist."); - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GOLD + key + ": " + EnumChatFormatting.YELLOW + wrapper.value)); - return; - } - - if(args.length < 3) throw new CommandException(getCommandUsage(sender)); - - String value = args[2]; - - if("set".equals(operator)) { - ConfigWrapper wrapper = ClientConfig.configMap.get(key); - if(wrapper == null) throw new CommandException("Key does not exist."); - - try { - wrapper.update(value); - ClientConfig.refresh(); - sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Value updated.")); - } catch(Exception ex) { - throw new CommandException("Error parsing type for " + wrapper.value.getClass().getSimpleName() + ": " + ex.getLocalizedMessage()); - } - - return; - } - - throw new CommandException(getCommandUsage(sender)); - } - - @SuppressWarnings("rawtypes") - @Override - public List addTabCompletionOptions(ICommandSender sender, String[] args) { - if(!(sender instanceof EntityPlayer)) return Collections.emptyList(); - if(args.length < 1) return Collections.emptyList(); - if(args.length == 1) return getListOfStringsMatchingLastWord(args, "list", "reload", "get", "set"); - String operator = args[0]; - if(args.length == 2 && ("get".equals(operator) || "set".equals(operator))) { - return getListOfStringsFromIterableMatchingLastWord(args, ClientConfig.configMap.keySet().stream().map(String::valueOf).collect(Collectors.toList())); - } - return Collections.emptyList(); + + @Override public void help(ICommandSender sender, String[] args) { + if(args.length >= 2) { + String command = args[1]; + if("help".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Shows usage for /ntmclient subcommands.")); + if("list".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Shows all client variable names and values.")); + if("reload".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Reads client variables from the config file.")); + if("get".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Shows value for the specified variable name.")); + if("set".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Sets a variable's value and saves it to the config file.")); + } else { + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmclient " + EnumChatFormatting.GOLD + "help " + EnumChatFormatting.RED + "")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmclient " + EnumChatFormatting.GOLD + "list")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmclient " + EnumChatFormatting.GOLD + "reload")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmclient " + EnumChatFormatting.GOLD + "get " + EnumChatFormatting.RED + "")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmclient " + EnumChatFormatting.GOLD + "set " + EnumChatFormatting.RED + " ")); + } } + + @Override public HashMap getConfigMap() { return ClientConfig.configMap; } + @Override public void refresh() { ClientConfig.refresh(); } + @Override public void reload() { ClientConfig.reload(); } + @Override public String getTitle() { return "CLIENT VARIABLES:"; } } diff --git a/src/main/java/com/hbm/commands/CommandReloadConfig.java b/src/main/java/com/hbm/commands/CommandReloadConfig.java new file mode 100644 index 000000000..fbe35111a --- /dev/null +++ b/src/main/java/com/hbm/commands/CommandReloadConfig.java @@ -0,0 +1,102 @@ +package com.hbm.commands; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import com.hbm.config.RunningConfig.ConfigWrapper; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; + +public abstract class CommandReloadConfig extends CommandBase { + + @Override + public boolean canCommandSenderUseCommand(ICommandSender sender) { + return sender instanceof EntityPlayer; + } + + public abstract void help(ICommandSender sender, String[] args); + public abstract HashMap getConfigMap(); + public abstract void refresh(); + public abstract void reload(); + public abstract String getTitle(); + + @Override + public void processCommand(ICommandSender sender, String[] args) { + + if(args.length < 1) throw new CommandException(getCommandUsage(sender)); + + String operator = args[0]; + + if("help".equals(operator)) { + help(sender, args); + return; + } + + if("list".equals(operator)) { + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + getTitle())); + for(Entry line : getConfigMap().entrySet()) { + sender.addChatMessage(new ChatComponentText(" " + EnumChatFormatting.GOLD + line.getKey() + ": " + EnumChatFormatting.YELLOW + line.getValue().value)); + } + return; + } + + if("reload".equals(operator)) { + reload(); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Variables loaded from config file.")); + return; + } + + if(args.length < 2) throw new CommandException(getCommandUsage(sender)); + + String key = args[1]; + + if("get".equals(operator)) { + ConfigWrapper wrapper = getConfigMap().get(key); + if(wrapper == null) throw new CommandException("Key does not exist."); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GOLD + key + ": " + EnumChatFormatting.YELLOW + wrapper.value)); + return; + } + + if(args.length < 3) throw new CommandException(getCommandUsage(sender)); + + String value = args[2]; + + if("set".equals(operator)) { + ConfigWrapper wrapper = getConfigMap().get(key); + if(wrapper == null) throw new CommandException("Key does not exist."); + + try { + wrapper.update(value); + refresh(); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Value updated.")); + } catch(Exception ex) { + throw new CommandException("Error parsing type for " + wrapper.value.getClass().getSimpleName() + ": " + ex.getLocalizedMessage()); + } + + return; + } + + throw new CommandException(getCommandUsage(sender)); + } + + @SuppressWarnings("rawtypes") + @Override + public List addTabCompletionOptions(ICommandSender sender, String[] args) { + if(!(sender instanceof EntityPlayer)) return Collections.emptyList(); + if(args.length < 1) return Collections.emptyList(); + if(args.length == 1) return getListOfStringsMatchingLastWord(args, "list", "reload", "get", "set"); + String operator = args[0]; + if(args.length == 2 && ("get".equals(operator) || "set".equals(operator))) { + return getListOfStringsFromIterableMatchingLastWord(args, getConfigMap().keySet().stream().map(String::valueOf).collect(Collectors.toList())); + } + return Collections.emptyList(); + } +} diff --git a/src/main/java/com/hbm/commands/CommandReloadServer.java b/src/main/java/com/hbm/commands/CommandReloadServer.java new file mode 100644 index 000000000..33c572141 --- /dev/null +++ b/src/main/java/com/hbm/commands/CommandReloadServer.java @@ -0,0 +1,45 @@ +package com.hbm.commands; + +import java.util.HashMap; + +import com.hbm.config.RunningConfig.ConfigWrapper; +import com.hbm.config.ServerConfig; + +import net.minecraft.command.ICommandSender; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; + +public class CommandReloadServer extends CommandReloadConfig { + + @Override + public String getCommandName() { + return "ntmserver"; + } + + @Override + public String getCommandUsage(ICommandSender sender) { + return "/ntmserver help"; + } + + @Override public void help(ICommandSender sender, String[] args) { + if(args.length >= 2) { + String command = args[1]; + if("help".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Shows usage for /ntmserver subcommands.")); + if("list".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Shows all server variable names and values.")); + if("reload".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Reads server variables from the config file.")); + if("get".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Shows value for the specified variable name.")); + if("set".equals(command)) sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Sets a variable's value and saves it to the config file.")); + } else { + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmserver " + EnumChatFormatting.GOLD + "help " + EnumChatFormatting.RED + "")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmserver " + EnumChatFormatting.GOLD + "list")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmserver " + EnumChatFormatting.GOLD + "reload")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmserver " + EnumChatFormatting.GOLD + "get " + EnumChatFormatting.RED + "")); + sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "/ntmserver " + EnumChatFormatting.GOLD + "set " + EnumChatFormatting.RED + " ")); + } + } + + @Override public HashMap getConfigMap() { return ServerConfig.configMap; } + @Override public void refresh() { ServerConfig.refresh(); } + @Override public void reload() { ServerConfig.reload(); } + @Override public String getTitle() { return "SERVER VARIABLES:"; } +} diff --git a/src/main/java/com/hbm/config/ClientConfig.java b/src/main/java/com/hbm/config/ClientConfig.java index 4d171cad7..2f5cec902 100644 --- a/src/main/java/com/hbm/config/ClientConfig.java +++ b/src/main/java/com/hbm/config/ClientConfig.java @@ -1,21 +1,12 @@ package com.hbm.config; import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.stream.JsonWriter; +import com.hbm.config.RunningConfig.ConfigWrapper; import com.hbm.main.MainRegistry; import com.hbm.util.Compat; import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; -import java.util.List; -import java.util.Map.Entry; // https://youtube.com/shorts/XTHZWqZt_AI public class ClientConfig { @@ -86,91 +77,10 @@ public class ClientConfig { } private static void readConfig(File config) { - - try { - JsonObject json = gson.fromJson(new FileReader(config), JsonObject.class); - - for(Entry line : configMap.entrySet()) { - - if(json.has(line.getKey())) { - JsonElement value = json.get(line.getKey()); - - try { - - //world's shittiest dynamic type parser - if(configMap.containsKey(line.getKey())) { - if(line.getValue().value instanceof String) configMap.get(line.getKey()).set(value.getAsString()); - if(line.getValue().value instanceof Float) configMap.get(line.getKey()).set(value.getAsFloat()); - if(line.getValue().value instanceof Double) configMap.get(line.getKey()).set(value.getAsDouble()); - if(line.getValue().value instanceof Integer) configMap.get(line.getKey()).set(value.getAsInt()); - if(line.getValue().value instanceof Boolean) configMap.get(line.getKey()).set(value.getAsBoolean()); - } - - //gson doesn't give me the option to read the raw value of a JsonPrimitive so we have to this shit effectively twice - //once to make sure that the parsed data matches with what's determined by the default, - //and a second time in the ConfigWrapper to add ease of reading the data without needing manual casts - - } catch(Exception ex) { - ex.printStackTrace(); - } - } - } - - } catch(Exception ex) { - ex.printStackTrace(); - } + RunningConfig.readConfig(config, configMap); } private static void writeConfig(File config) { - - try { - JsonWriter writer = new JsonWriter(new FileWriter(config)); - writer.setIndent(" "); - writer.beginObject(); - - writer.name("info").value("This file can be edited ingame using the /ntmclient command."); - - List keys = new ArrayList(); - keys.addAll(configMap.keySet()); - Collections.sort(keys); //readability is cool - - for(String key : keys) { - - ConfigWrapper wrapper = configMap.get(key); - Object value = wrapper.value; - //this sucks and i am too stupid to come up with something better - if(value instanceof String) writer.name(key).value((String) value); - if(value instanceof Float) writer.name(key).value((Float) value); - if(value instanceof Double) writer.name(key).value((Double) value); - if(value instanceof Integer) writer.name(key).value((Integer) value); - if(value instanceof Boolean) writer.name(key).value((Boolean) value); - } - - writer.endObject(); - writer.close(); - } catch(IOException e) { - e.printStackTrace(); - } - } - - public static class ConfigWrapper { - public T value; - - public ConfigWrapper(T o) { - this.value = o; - } - - public T get() { return value; } - public void set(T value) { this.value = value; } - - public void update(String param) { - Object stupidBufferObject = null; // wahh wahh can't cast Float to T wahh wahh shut the fuck up - if(value instanceof String) stupidBufferObject = param; - if(value instanceof Float) stupidBufferObject = Float.parseFloat(param); - if(value instanceof Double) stupidBufferObject = Double.parseDouble(param); - if(value instanceof Integer) stupidBufferObject = Integer.parseInt(param); - if(value instanceof Boolean) stupidBufferObject = Boolean.parseBoolean(param); - if(stupidBufferObject != null) this.value = (T) stupidBufferObject; - } + RunningConfig.writeConfig(config, configMap, "This file can be edited ingame using the /ntmclient command."); } } diff --git a/src/main/java/com/hbm/config/RunningConfig.java b/src/main/java/com/hbm/config/RunningConfig.java new file mode 100644 index 000000000..66ebe9193 --- /dev/null +++ b/src/main/java/com/hbm/config/RunningConfig.java @@ -0,0 +1,110 @@ +package com.hbm.config; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.stream.JsonWriter; + +public class RunningConfig { + + public static final Gson gson = new Gson(); + + public static void readConfig(File config, HashMap configMap) { + + try { + JsonObject json = gson.fromJson(new FileReader(config), JsonObject.class); + + for(Entry line : configMap.entrySet()) { + + if(json.has(line.getKey())) { + JsonElement value = json.get(line.getKey()); + + try { + + //world's shittiest dynamic type parser + if(configMap.containsKey(line.getKey())) { + if(line.getValue().value instanceof String) configMap.get(line.getKey()).set(value.getAsString()); + if(line.getValue().value instanceof Float) configMap.get(line.getKey()).set(value.getAsFloat()); + if(line.getValue().value instanceof Double) configMap.get(line.getKey()).set(value.getAsDouble()); + if(line.getValue().value instanceof Integer) configMap.get(line.getKey()).set(value.getAsInt()); + if(line.getValue().value instanceof Boolean) configMap.get(line.getKey()).set(value.getAsBoolean()); + } + + //gson doesn't give me the option to read the raw value of a JsonPrimitive so we have to this shit effectively twice + //once to make sure that the parsed data matches with what's determined by the default, + //and a second time in the ConfigWrapper to add ease of reading the data without needing manual casts + + } catch(Exception ex) { + ex.printStackTrace(); + } + } + } + + } catch(Exception ex) { + ex.printStackTrace(); + } + } + + public static void writeConfig(File config, HashMap configMap, String info) { + + try { + JsonWriter writer = new JsonWriter(new FileWriter(config)); + writer.setIndent(" "); + writer.beginObject(); + + writer.name("info").value(info); + + List keys = new ArrayList(); + keys.addAll(configMap.keySet()); + Collections.sort(keys); //readability is cool + + for(String key : keys) { + + ConfigWrapper wrapper = configMap.get(key); + Object value = wrapper.value; + //this sucks and i am too stupid to come up with something better + if(value instanceof String) writer.name(key).value((String) value); + if(value instanceof Float) writer.name(key).value((Float) value); + if(value instanceof Double) writer.name(key).value((Double) value); + if(value instanceof Integer) writer.name(key).value((Integer) value); + if(value instanceof Boolean) writer.name(key).value((Boolean) value); + } + + writer.endObject(); + writer.close(); + } catch(IOException e) { + e.printStackTrace(); + } + } + + public static class ConfigWrapper { + public T value; + + public ConfigWrapper(T o) { + this.value = o; + } + + public T get() { return value; } + public void set(T value) { this.value = value; } + + public void update(String param) { + Object stupidBufferObject = null; // wahh wahh can't cast Float to T wahh wahh shut the fuck up + if(value instanceof String) stupidBufferObject = param; + if(value instanceof Float) stupidBufferObject = Float.parseFloat(param); + if(value instanceof Double) stupidBufferObject = Double.parseDouble(param); + if(value instanceof Integer) stupidBufferObject = Integer.parseInt(param); + if(value instanceof Boolean) stupidBufferObject = Boolean.parseBoolean(param); + if(stupidBufferObject != null) this.value = (T) stupidBufferObject; + } + } +} diff --git a/src/main/java/com/hbm/config/ServerConfig.java b/src/main/java/com/hbm/config/ServerConfig.java new file mode 100644 index 000000000..fd9586113 --- /dev/null +++ b/src/main/java/com/hbm/config/ServerConfig.java @@ -0,0 +1,58 @@ +package com.hbm.config; + +import java.io.File; +import java.util.HashMap; + +import com.google.gson.Gson; +import com.hbm.main.MainRegistry; + +public class ServerConfig extends RunningConfig { + + public static final Gson gson = new Gson(); + public static HashMap configMap = new HashMap(); + + public static ConfigWrapper DAMAGE_COMPATIBILITY_MODE = new ConfigWrapper(false); + public static ConfigWrapper MINE_AP_DAMAGE = new ConfigWrapper(10F); + public static ConfigWrapper MINE_HE_DAMAGE = new ConfigWrapper(35F); + public static ConfigWrapper MINE_SHRAP_DAMAGE = new ConfigWrapper(7.5F); + public static ConfigWrapper MINE_NUKE_DAMAGE = new ConfigWrapper(100F); + + private static void initDefaults() { + configMap.put("DAMAGE_COMPATIBILITY_MODE", DAMAGE_COMPATIBILITY_MODE); + configMap.put("MINE_AP_DAMAGE", MINE_AP_DAMAGE); + configMap.put("MINE_HE_DAMAGE", MINE_HE_DAMAGE); + configMap.put("MINE_SHRAP_DAMAGE", MINE_SHRAP_DAMAGE); + configMap.put("MINE_NUKE_DAMAGE", MINE_NUKE_DAMAGE); + } + + /** Initializes defaults, then reads the config file if it exists, then writes the config file. */ + public static void initConfig() { + initDefaults(); + File folder = MainRegistry.configHbmDir; + File config = new File(folder.getAbsolutePath() + File.separatorChar + "hbmServer.json"); + if(config.exists()) readConfig(config); + refresh(); + } + + /** Writes over the config file using the running config. */ + public static void refresh() { + File folder = MainRegistry.configHbmDir; + File config = new File(folder.getAbsolutePath() + File.separatorChar + "hbmServer.json"); + writeConfig(config); + } + + /** Writes over the running config using the config file. */ + public static void reload() { + File folder = MainRegistry.configHbmDir; + File config = new File(folder.getAbsolutePath() + File.separatorChar + "hbmServer.json"); + if(config.exists()) readConfig(config); + } + + private static void readConfig(File config) { + RunningConfig.readConfig(config, configMap); + } + + private static void writeConfig(File config) { + RunningConfig.writeConfig(config, configMap, "This file can be edited ingame using the /ntmserver command."); + } +} diff --git a/src/main/java/com/hbm/explosion/ExplosionNukeSmall.java b/src/main/java/com/hbm/explosion/ExplosionNukeSmall.java index cca47893b..47067d8b2 100644 --- a/src/main/java/com/hbm/explosion/ExplosionNukeSmall.java +++ b/src/main/java/com/hbm/explosion/ExplosionNukeSmall.java @@ -12,7 +12,7 @@ import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; -public class ExplosionNukeSmall { +@Deprecated public class ExplosionNukeSmall { public static void explode(World world, double posX, double posY, double posZ, MukeParams params) { diff --git a/src/main/java/com/hbm/items/ModItems.java b/src/main/java/com/hbm/items/ModItems.java index 598003562..3b2feed15 100644 --- a/src/main/java/com/hbm/items/ModItems.java +++ b/src/main/java/com/hbm/items/ModItems.java @@ -3022,7 +3022,8 @@ public class ModItems { iv_empty = new ItemSimpleConsumable().setUseActionServer((stack, user) -> { if(user.hurtResistantTime <= 0) { ItemSimpleConsumable.giveSoundAndDecrement(stack, user, "hbm:item.syringe", new ItemStack(ModItems.iv_blood)); - user.attackEntityFrom(DamageSource.magic, 5F); + user.setHealth(Math.max(user.getHealth() - 5F, 0F)); + if(user.getHealth() <= 0) user.onDeath(DamageSource.magic); } }).setUnlocalizedName("iv_empty").setCreativeTab(MainRegistry.consumableTab).setTextureName(RefStrings.MODID + ":iv_empty"); diff --git a/src/main/java/com/hbm/items/weapon/sedna/factory/XFactory762mm.java b/src/main/java/com/hbm/items/weapon/sedna/factory/XFactory762mm.java index b17c15d78..f63275b9a 100644 --- a/src/main/java/com/hbm/items/weapon/sedna/factory/XFactory762mm.java +++ b/src/main/java/com/hbm/items/weapon/sedna/factory/XFactory762mm.java @@ -191,7 +191,7 @@ public class XFactory762mm { .addBus("LIFT", new BusAnimationSequence().hold(200).addPos(30, 0, 0, 500, IType.SIN_FULL).holdUntil(1200).addPos(0, 0, 0, 500, IType.SIN_FULL)) .addBus("SHOW_CLIP", new BusAnimationSequence().setPos(1, 1, 1)) .addBus("CLIP", new BusAnimationSequence().setPos(2, -3, 0).hold(250).addPos(0.5, 1, 0, 500, IType.SIN_DOWN).addPos(0, 0, 0, 250, IType.SIN_FULL).hold(400).addPos(-0.5, 0.5, 0, 150).addPos(-3, -3, 0, 250, IType.SIN_UP)) - .addBus("BULLETS", new BusAnimationSequence().setPos(2, -4, 0).hold(250).addPos(0.5, 1, 0, 500, IType.SIN_DOWN).addPos(0, 0, 0, 250, IType.SIN_FULL).hold(150).addPos(0, -1.5, 0, 250, IType.SIN_DOWN)); + .addBus("BULLETS", new BusAnimationSequence().setPos(2, -3, 0).hold(250).addPos(0.5, 1, 0, 500, IType.SIN_DOWN).addPos(0, 0, 0, 250, IType.SIN_FULL).hold(150).addPos(0, -1.5, 0, 250, IType.SIN_DOWN)); case JAMMED: return new BusAnimation() .addBus("LIFT", new BusAnimationSequence().hold(250).addPos(-15, 0, 0, 500, IType.SIN_FULL).holdUntil(1650).addPos(0, 0, 0, 500, IType.SIN_FULL)) .addBus("BOLT_TURN", new BusAnimationSequence().hold(250).addPos(0, 0, turn, 150).holdUntil(1250).addPos(0, 0, 0, 150)) diff --git a/src/main/java/com/hbm/main/MainRegistry.java b/src/main/java/com/hbm/main/MainRegistry.java index 94e2e5afa..bb9616014 100644 --- a/src/main/java/com/hbm/main/MainRegistry.java +++ b/src/main/java/com/hbm/main/MainRegistry.java @@ -861,7 +861,9 @@ public class MainRegistry { FalloutConfigJSON.initialize(); ItemPoolConfigJSON.initialize(); + ClientConfig.initConfig(); + ServerConfig.initConfig(); TileEntityNukeCustom.registerBombItems(); ArmorUtil.register(); @@ -948,6 +950,7 @@ public class MainRegistry { event.registerServerCommand(new CommandSatellites()); event.registerServerCommand(new CommandRadiation()); event.registerServerCommand(new CommandPacketInfo()); + event.registerServerCommand(new CommandReloadServer()); } @EventHandler diff --git a/src/main/java/com/hbm/main/ModEventHandler.java b/src/main/java/com/hbm/main/ModEventHandler.java index 292c2a435..bdba621ca 100644 --- a/src/main/java/com/hbm/main/ModEventHandler.java +++ b/src/main/java/com/hbm/main/ModEventHandler.java @@ -114,6 +114,7 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; import net.minecraftforge.event.entity.player.PlayerUseItemEvent; import net.minecraftforge.event.world.BlockEvent.BreakEvent; +import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.event.world.WorldEvent; import org.apache.commons.lang3.math.NumberUtils; import org.apache.logging.log4j.Level; @@ -1231,6 +1232,18 @@ public class ModEventHandler { }*/ } + @SubscribeEvent + public void onChunkLoad(ChunkEvent.Load event) { + + //test for automatic in-world block replacement + + /*for(int x = 0; x < 16; x++) for(int y = 0; y < 255; y++) for(int z = 0; z < 16; z++) { + if(event.getChunk().getBlock(x, y, z) instanceof MachineArcFurnace) { + event.getChunk().func_150807_a(x, y, z, Blocks.air, 0); + } + }*/ + } + @SubscribeEvent public void onPlayerClone(net.minecraftforge.event.entity.player.PlayerEvent.Clone event) { diff --git a/src/main/java/com/hbm/render/anim/BusAnimationSequence.java b/src/main/java/com/hbm/render/anim/BusAnimationSequence.java index 640c22318..bd1630630 100644 --- a/src/main/java/com/hbm/render/anim/BusAnimationSequence.java +++ b/src/main/java/com/hbm/render/anim/BusAnimationSequence.java @@ -82,6 +82,7 @@ public class BusAnimationSequence { /** Repeats the previous keyframe for a duration depending on the previous keyframes. Useful for getting different buses to sync up. */ public BusAnimationSequence holdUntil(int end) { int duration = end - getTotalTime(); + //FIXME: holdUntil breaks as soon as the animation speed is not 1 return hold(duration); } diff --git a/src/main/java/com/hbm/util/EntityDamageUtil.java b/src/main/java/com/hbm/util/EntityDamageUtil.java index 03c2363d2..6ba1791ce 100644 --- a/src/main/java/com/hbm/util/EntityDamageUtil.java +++ b/src/main/java/com/hbm/util/EntityDamageUtil.java @@ -3,6 +3,8 @@ package com.hbm.util; import java.lang.reflect.Method; import java.util.List; +import com.hbm.config.ServerConfig; + import cpw.mods.fml.relauncher.ReflectionHelper; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; @@ -21,7 +23,8 @@ import net.minecraftforge.common.ForgeHooks; public class EntityDamageUtil { - public static boolean attackEntityFromIgnoreIFrame(Entity victim, DamageSource src, float damage) { + /** Shitty hack, if the first attack fails, it retries with damage + previous damage, allowing damage to penetrate */ + @Deprecated public static boolean attackEntityFromIgnoreIFrame(Entity victim, DamageSource src, float damage) { if(!victim.attackEntityFrom(src, damage)) { @@ -38,6 +41,7 @@ public class EntityDamageUtil { } } + /** New and improved entity damage calc - only use this one */ public static boolean attackEntityFromNT(EntityLivingBase living, DamageSource source, float amount, boolean ignoreIFrame, boolean allowSpecialCancel, double knockbackMultiplier, float pierceDT, float pierce) { if(living instanceof EntityPlayerMP && source.getEntity() instanceof EntityPlayer) { EntityPlayerMP playerMP = (EntityPlayerMP) living; @@ -45,14 +49,55 @@ public class EntityDamageUtil { if(!playerMP.canAttackPlayer(attacker)) return false; //handles wack-ass no PVP rule as well as scoreboard friendly fire } DamageResistanceHandler.setup(pierceDT, pierce); - living.attackEntityFrom(source, 0F); boolean ret = attackEntityFromNTInternal(living, source, amount, ignoreIFrame, allowSpecialCancel, knockbackMultiplier); - //boolean ret = living.attackEntityFrom(source, amount); DamageResistanceHandler.reset(); return ret; } - + private static boolean attackEntityFromNTInternal(EntityLivingBase living, DamageSource source, float amount, boolean ignoreIFrame, boolean allowSpecialCancel, double knockbackMultiplier) { + boolean superCompatibility = ServerConfig.DAMAGE_COMPATIBILITY_MODE.get(); + return superCompatibility + ? attackEntitySuperCompatibility(living, source, amount, ignoreIFrame, allowSpecialCancel, knockbackMultiplier) + : attackEntitySEDNAPatch(living, source, amount, ignoreIFrame, allowSpecialCancel, knockbackMultiplier); + } + + /** + * MK2 SEDNA damage system, currently untested. An even hackier, yet more compatible solution using the vanilla damage calc directly but tweaking certain apsects. + * Limitation: Does not apply DR piercing to vanilla armor + */ + private static boolean attackEntitySuperCompatibility(EntityLivingBase living, DamageSource source, float amount, boolean ignoreIFrame, boolean allowSpecialCancel, double knockbackMultiplier) { + //disable iframes + if(ignoreIFrame) { living.lastDamage = 0F; living.hurtResistantTime = 0; } + //cache last velocity + double motionX = living.motionX; + double motionY = living.motionX; + double motionZ = living.motionX; + //bam! + boolean ret = living.attackEntityFrom(source, amount); + //restore last velocity + living.motionX = motionX; + living.motionY = motionY; + living.motionZ = motionZ; + //apply own knockback + Entity entity = source.getEntity(); + if(entity != null) { + double deltaX = entity.posX - living.posX; + double deltaZ; + + for(deltaZ = entity.posZ - living.posZ; deltaX * deltaX + deltaZ * deltaZ < 1.0E-4D; deltaZ = (Math.random() - Math.random()) * 0.01D) { + deltaX = (Math.random() - Math.random()) * 0.01D; + } + + living.attackedAtYaw = (float) (Math.atan2(deltaZ, deltaX) * 180.0D / Math.PI) - living.rotationYaw; + if(knockbackMultiplier > 0) knockBack(living, entity, amount, deltaX, deltaZ, knockbackMultiplier); + } + return ret; + } + + /** MK1 SEDNA damage system, basically re-implements the vanilla code (only from Entity, child class code is effectively ignored) with some adjustments */ + private static boolean attackEntitySEDNAPatch(EntityLivingBase living, DamageSource source, float amount, boolean ignoreIFrame, boolean allowSpecialCancel, double knockbackMultiplier) { + living.attackEntityFrom(source, 0F); + if(ignoreIFrame) living.lastDamage = 0F; if(ForgeHooks.onLivingAttack(living, source, amount) && allowSpecialCancel) return false; if(living.isEntityInvulnerable()) return false; if(living.worldObj.isRemote) return false; @@ -183,9 +228,7 @@ public class EntityDamageUtil { return amount; } - public static void damageArmorNT(EntityLivingBase living, float amount) { - - } + public static void damageArmorNT(EntityLivingBase living, float amount) { } /** Currently just a copy of the vanilla damage code */ @Deprecated public static boolean attackEntityFromNT(EntityLivingBase living, DamageSource source, float amount) { diff --git a/src/main/resources/assets/hbm/textures/blocks/glass_polarized.png b/src/main/resources/assets/hbm/textures/blocks/glass_polarized.png new file mode 100644 index 000000000..29a0ce9d6 Binary files /dev/null and b/src/main/resources/assets/hbm/textures/blocks/glass_polarized.png differ diff --git a/src/main/resources/assets/hbm/textures/blocks/glass_polarized_ct.png b/src/main/resources/assets/hbm/textures/blocks/glass_polarized_ct.png new file mode 100644 index 000000000..9ba4239ea Binary files /dev/null and b/src/main/resources/assets/hbm/textures/blocks/glass_polarized_ct.png differ diff --git a/src/main/resources/assets/hbm/textures/items/ingot_metal_sheet.png b/src/main/resources/assets/hbm/textures/items/ingot_metal_sheet.png index 456950b8b..27e251a79 100644 Binary files a/src/main/resources/assets/hbm/textures/items/ingot_metal_sheet.png and b/src/main/resources/assets/hbm/textures/items/ingot_metal_sheet.png differ