aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/CODEOWNERS2
-rw-r--r--Update Notes/2.1.md1
-rw-r--r--build.gradle.kts193
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java18
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java75
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java9
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/EntityViewerCommand.java81
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/AgeModifier.java30
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/ChargedModifier.java17
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewer.java177
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewerModifier.java8
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EquipmentModifier.java72
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/GUIClientPlayer.java40
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/HorseModifier.java66
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/InvisibleModifier.java12
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/RidingModifier.java14
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/SkinModifier.java46
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/WitherModifier.java29
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java199
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityAgeable.java12
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityArmorStand.java12
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorMinecraft.java14
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java1
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityHorse.java17
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntitySkeleton.java17
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java4
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java10
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java38
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java2
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java257
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java442
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java5
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java309
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java24
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java169
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java59
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java256
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java33
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/JsonUtils.java42
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/SkytilsCompat.java82
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java17
-rw-r--r--src/main/resources/assets/notenoughupdates/dream.json49
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/crafting_table_tall.pngbin0 -> 12019 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/entity_viewer.pngbin0 -> 8085 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe.pngbin889 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe_tall.pngbin0 -> 9257 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/mob_loot_tall.pngbin0 -> 9503 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/tab.pngbin0 -> 1247 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe.pngbin8633 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe_tall.pngbin0 -> 9218 bytes
-rw-r--r--src/main/resources/mixins.notenoughupdates.json7
54 files changed, 2302 insertions, 705 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 00000000..2381ceb8
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,2 @@
+/src/main/java/io/github/moulberry/notenoughupdates/recipes/* @romangraef
+/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java @romangraef
diff --git a/Update Notes/2.1.md b/Update Notes/2.1.md
index 18a4ba8a..dff52a65 100644
--- a/Update Notes/2.1.md
+++ b/Update Notes/2.1.md
@@ -19,6 +19,7 @@
- Added support for official Hypixel wiki, can be toggled in /neu misc - DeDiamondPro
### **Minor Changes:**
- Add built-in recipes for forge crafts - nea89
+- Add mob drop viewer in the recipe viewer - nea89
- Add Stranded Villager Trades to the item list - nea89
- Make cata xp in /pv be calculated on how many runs you have and shows master mode xp rates
- Added a config option to hide Dwarven Mines waypoints when already at the location - Lulonaut
diff --git a/build.gradle.kts b/build.gradle.kts
index e134387e..3ffaf61a 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,58 +1,76 @@
-import java.io.ByteArrayOutputStream
import net.minecraftforge.gradle.user.ReobfMappingType
+import java.io.ByteArrayOutputStream
+
plugins {
- java
- id("net.minecraftforge.gradle.forge") version "6f5327738df"
- id("com.github.johnrengelman.shadow") version "6.1.0"
- id("org.spongepowered.mixin") version "d75e32e"
+ java
+ id("net.minecraftforge.gradle.forge") version "6f5327738df"
+ id("com.github.johnrengelman.shadow") version "6.1.0"
+ id("org.spongepowered.mixin") version "d75e32e"
}
group = "io.github.moulberry"
val baseVersion = "2.1"
-var buildVersion = properties["BUILD_VERSION"]
-if (buildVersion == null) {
- val stdout = ByteArrayOutputStream()
- val execResult = exec {
- commandLine("git", "describe", "--always", "--first-parent", "--abbrev=7")
- standardOutput = stdout
- }
- if (execResult.exitValue == 0)
- buildVersion = String(stdout.toByteArray()).trim()
+val buildExtra = mutableListOf<String>()
+val buildVersion = properties["BUILD_VERSION"] as? String
+if (buildVersion != null)
+ buildExtra.add(buildVersion)
+val githubCi = properties["GITHUB_ACTIONS"] as? String
+if (githubCi == "true")
+ buildExtra.add("ci")
+
+val stdout = ByteArrayOutputStream()
+val execResult = exec {
+ commandLine("git", "describe", "--always", "--first-parent", "--abbrev=7")
+ standardOutput = stdout
+ isIgnoreExitValue = true
+}
+if (execResult.exitValue == 0) {
+ buildExtra.add(String(stdout.toByteArray()).trim())
+}
+
+val gitDiffStdout = ByteArrayOutputStream()
+val gitDiffResult = exec {
+ commandLine("git", "status", "--porcelain")
+ standardOutput = gitDiffStdout
+ isIgnoreExitValue = true
+}
+if (gitDiffStdout.toByteArray().isNotEmpty()) {
+ buildExtra.add("dirty")
}
-version = baseVersion + (buildVersion?.let { "+$it" } ?: "")
+version = baseVersion + (if (buildExtra.isEmpty()) "" else buildExtra.joinToString(prefix = "+", separator = "."))
// Toolchains:
java {
- // Forge Gradle currently prevents using the toolchain: toolchain.languageVersion.set(JavaLanguageVersion.of(8))
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ // Forge Gradle currently prevents using the toolchain: toolchain.languageVersion.set(JavaLanguageVersion.of(8))
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
}
minecraft {
- version = "1.8.9-11.15.1.2318-1.8.9"
- runDir = "run"
- mappings = "stable_22"
- clientJvmArgs.addAll(
- listOf(
- "-Dmixin.debug=true",
- "-Dasmhelper.verbose=true"
- )
- )
- clientRunArgs.addAll(
- listOf(
- "--tweakClass org.spongepowered.asm.launch.MixinTweaker",
- "--mixin mixins.notenoughupdates.json"
- )
- )
+ version = "1.8.9-11.15.1.2318-1.8.9"
+ runDir = "run"
+ mappings = "stable_22"
+ clientJvmArgs.addAll(
+ listOf(
+ "-Dmixin.debug=true",
+ "-Dasmhelper.verbose=true"
+ )
+ )
+ clientRunArgs.addAll(
+ listOf(
+ "--tweakClass org.spongepowered.asm.launch.MixinTweaker",
+ "--mixin mixins.notenoughupdates.json"
+ )
+ )
}
mixin {
- add(sourceSets.main.get(), "mixins.notenoughupdates.refmap.json")
+ add(sourceSets.main.get(), "mixins.notenoughupdates.refmap.json")
}
// Dependencies:
@@ -67,14 +85,14 @@ dependencies {
annotationProcessor("org.spongepowered:mixin:0.7.11-SNAPSHOT")
implementation("com.fasterxml.jackson.core:jackson-core:2.13.1")
implementation("info.bliki.wiki:bliki-core:3.1.0")
- testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
+ testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
}
// Tasks:
tasks.withType(JavaCompile::class) {
- options.encoding = "UTF-8"
+ options.encoding = "UTF-8"
}
tasks.named<Test>("test") {
@@ -82,72 +100,61 @@ tasks.named<Test>("test") {
}
tasks.withType(Jar::class) {
- archiveBaseName.set("NotEnoughUpdates")
- manifest.attributes.run {
- this["Main-Class"] = "NotSkyblockAddonsInstallerFrame"
- this["TweakClass"] = "org.spongepowered.asm.launch.MixinTweaker"
- this["MixinConfigs"] = "mixins.notenoughupdates.json"
- this["FMLCorePluginContainsFMLMod"] = "true"
- this["ForceLoadAsMod"] = "true"
- this["FMLAT"] = "notenoughupdates_at.cfg"
- }
+ archiveBaseName.set("NotEnoughUpdates")
+ manifest.attributes.run {
+ this["Main-Class"] = "NotSkyblockAddonsInstallerFrame"
+ this["TweakClass"] = "org.spongepowered.asm.launch.MixinTweaker"
+ this["MixinConfigs"] = "mixins.notenoughupdates.json"
+ this["FMLCorePluginContainsFMLMod"] = "true"
+ this["ForceLoadAsMod"] = "true"
+ this["FMLAT"] = "notenoughupdates_at.cfg"
+ }
}
tasks.shadowJar {
- archiveClassifier.set("dep")
- exclude(
- "module-info.class",
- "LICENSE.txt"
- )
- dependencies {
- include(dependency("org.spongepowered:mixin:0.7.11-SNAPSHOT"))
-
- include(dependency("commons-io:commons-io"))
- include(dependency("org.apache.commons:commons-lang3"))
- include(dependency("com.fasterxml.jackson.core:jackson-databind:2.10.2"))
- include(dependency("com.fasterxml.jackson.core:jackson-annotations:2.10.2"))
- include(dependency("com.fasterxml.jackson.core:jackson-core:2.10.2"))
-
- include(dependency("info.bliki.wiki:bliki-core:3.1.0"))
- include(dependency("org.slf4j:slf4j-api:1.7.18"))
- include(dependency("org.luaj:luaj-jse:3.0.1"))
- }
- fun relocate(name: String) = relocate(name, "io.github.moulberry.notenoughupdates.deps.$name")
- relocate("com.fasterxml.jackson")
- relocate("org.eclipse")
- relocate("org.slf4j")
+ archiveClassifier.set("dep")
+ exclude(
+ "module-info.class",
+ "LICENSE.txt"
+ )
+ dependencies {
+ include(dependency("org.spongepowered:mixin:0.7.11-SNAPSHOT"))
+
+ include(dependency("commons-io:commons-io"))
+ include(dependency("org.apache.commons:commons-lang3"))
+ include(dependency("com.fasterxml.jackson.core:jackson-databind:2.10.2"))
+ include(dependency("com.fasterxml.jackson.core:jackson-annotations:2.10.2"))
+ include(dependency("com.fasterxml.jackson.core:jackson-core:2.10.2"))
+
+ include(dependency("info.bliki.wiki:bliki-core:3.1.0"))
+ include(dependency("org.slf4j:slf4j-api:1.7.18"))
+ include(dependency("org.luaj:luaj-jse:3.0.1"))
+ }
+ fun relocate(name: String) = relocate(name, "io.github.moulberry.notenoughupdates.deps.$name")
+ relocate("com.fasterxml.jackson")
+ relocate("org.eclipse")
+ relocate("org.slf4j")
}
tasks.build.get().dependsOn(tasks.shadowJar)
reobf {
- create("shadowJar") {
- mappingType = ReobfMappingType.SEARGE
- }
+ create("shadowJar") {
+ mappingType = ReobfMappingType.SEARGE
+ }
}
tasks.processResources {
- from(sourceSets.main.get().resources.srcDirs)
- filesMatching("mcmod.info") {
- expand(
- "version" to project.version,
- "mcversion" to minecraft.version
- )
- }
- rename("(.+_at.cfg)".toPattern(), "META-INF/$1")
-}
-
-val moveResources by tasks.creating {
- doLast {
- ant.withGroovyBuilder {
- "move"(
- "file" to "$buildDir/resources/main",
- "todir" to "$buildDir/classes/java"
- )
- }
- }
- dependsOn(tasks.processResources)
-}
-
-tasks.classes { dependsOn(moveResources) }
+ from(sourceSets.main.get().resources.srcDirs)
+ filesMatching("mcmod.info") {
+ expand(
+ "version" to project.version,
+ "mcversion" to minecraft.version
+ )
+ }
+ rename("(.+_at.cfg)".toPattern(), "META-INF/$1")
+}
+sourceSets.main {
+ output.setResourcesDir(file("$buildDir/classes/java/main"))
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
index abe0bdcf..6572431b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
@@ -895,12 +895,12 @@ public class NEUManager {
String clickcommand = item.get("clickcommand").getAsString();
switch (clickcommand.intern()) {
case "viewrecipe":
- displayGuiItemRecipe(internalName, null);
+ displayGuiItemRecipe(internalName);
break;
case "viewoption":
neu.sendChatMessage("/viewpotion " + internalName.split(";")[0].toLowerCase(Locale.ROOT));
}
- displayGuiItemRecipe(internalName, "");
+ displayGuiItemRecipe(internalName);
}
public void showRecipe(String internalName) {
@@ -990,16 +990,16 @@ public class NEUManager {
List<NeuRecipe> usages = getAvailableUsagesFor(internalName);
if (usages.isEmpty()) return false;
Minecraft.getMinecraft().displayGuiScreen(
- new GuiItemRecipe("Item Usages", usages, this));
+ new GuiItemRecipe(usages, this));
return true;
}
- public boolean displayGuiItemRecipe(String internalName, String text) {
+ public boolean displayGuiItemRecipe(String internalName) {
if (!recipesMap.containsKey(internalName)) return false;
List<NeuRecipe> recipes = getAvailableRecipesFor(internalName);
if (recipes.isEmpty()) return false;
Minecraft.getMinecraft().displayGuiScreen(
- new GuiItemRecipe(text != null ? text : "Item Recipe", recipes, this));
+ new GuiItemRecipe(recipes, this));
return true;
}
@@ -1010,7 +1010,7 @@ public class NEUManager {
public boolean failViewItem(String text) {
if (viewItemAttemptID != null && !viewItemAttemptID.isEmpty()) {
if (System.currentTimeMillis() - viewItemAttemptTime < 500) {
- return displayGuiItemRecipe(viewItemAttemptID, text);
+ return displayGuiItemRecipe(viewItemAttemptID);
}
}
return false;
@@ -1570,4 +1570,10 @@ public class NEUManager {
}
}
}
+
+ public ItemStack createItem(String internalname) {
+ JsonObject jsonObject = itemMap.get(internalname);
+ if (jsonObject == null) return null;
+ return jsonToStack(jsonObject);
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
index 7965abae..8d0955bb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
@@ -1358,7 +1358,7 @@ public class NEUOverlay extends Gui {
}
if (getSortMode() == SORT_MODE_ALL) {
- return !internalname.matches(mobRegex);
+ return NotEnoughUpdates.INSTANCE.config.itemlist.alwaysShowMonsters || !internalname.matches(mobRegex);
} else if (getSortMode() == SORT_MODE_MOB) {
return internalname.matches(mobRegex);
} else if (getSortMode() == SORT_MODE_PET) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java b/src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java
new file mode 100644
index 00000000..2a5cda92
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java
@@ -0,0 +1,75 @@
+package io.github.moulberry.notenoughupdates;
+
+import com.google.gson.JsonObject;
+import net.minecraft.client.resources.IResourcePack;
+import net.minecraft.client.resources.data.IMetadataSection;
+import net.minecraft.client.resources.data.IMetadataSerializer;
+import net.minecraft.util.ResourceLocation;
+
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.HashSet;
+import java.util.Set;
+
+public class NEURepoResourcePack implements IResourcePack {
+
+ File repoLocation;
+ Set<String> resourceDomains = new HashSet<>();
+
+ public NEURepoResourcePack(File repoLocation, String domain) {
+ this.repoLocation = repoLocation;
+ resourceDomains.add(domain);
+ }
+
+ public boolean loadRepoLocation() {
+ if (repoLocation != null) return true;
+ NotEnoughUpdates instance = NotEnoughUpdates.INSTANCE;
+ if (instance == null) return false;
+ NEUManager manager = instance.manager;
+ if (manager == null) return false;
+ repoLocation = manager.repoLocation;
+ return repoLocation != null;
+ }
+
+ public File getFileForResource(ResourceLocation loc) {
+ if (repoLocation == null) {
+ if (!loadRepoLocation())
+ return null;
+ }
+ if (!"neurepo".equals(loc.getResourceDomain())) {
+ return null;
+ }
+ return new File(repoLocation, loc.getResourcePath());
+ }
+
+ @Override
+ public InputStream getInputStream(ResourceLocation resourceLocation) throws IOException {
+ return new BufferedInputStream(new FileInputStream(getFileForResource(resourceLocation)));
+ }
+
+ @Override
+ public boolean resourceExists(ResourceLocation resourceLocation) {
+ File file = getFileForResource(resourceLocation);
+ return file != null && file.exists();
+ }
+
+ @Override
+ public Set<String> getResourceDomains() {
+ return resourceDomains;
+ }
+
+ @Override
+ public <T extends IMetadataSection> T getPackMetadata(IMetadataSerializer iMetadataSerializer, String s) throws IOException {
+ return iMetadataSerializer.parseMetadataSection(s, new JsonObject());
+ }
+
+ @Override
+ public BufferedImage getPackImage() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getPackName() {
+ return "NEU Repo Resources";
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index 0a77c677..6b2fd09e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -35,6 +35,7 @@ import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.Custom
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.DwarvenMinesTextures;
import io.github.moulberry.notenoughupdates.miscgui.CalendarOverlay;
import io.github.moulberry.notenoughupdates.miscgui.InventoryStorageSelector;
+import io.github.moulberry.notenoughupdates.mixins.AccessorMinecraft;
import io.github.moulberry.notenoughupdates.options.NEUConfig;
import io.github.moulberry.notenoughupdates.overlays.FuelBar;
import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
@@ -58,6 +59,7 @@ import net.minecraft.world.biome.BiomeGenJungle;
import net.minecraft.world.biome.BiomeGenMesa;
import net.minecraft.world.biome.BiomeGenSnow;
import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
@@ -160,6 +162,13 @@ public class NotEnoughUpdates {
return this.neuDir;
}
+ public NotEnoughUpdates() {
+ // Budget Construction Event
+ ((AccessorMinecraft) FMLClientHandler.instance().getClient())
+ .onGetDefaultResourcePacks()
+ .add(new NEURepoResourcePack(null, "neurepo"));
+ }
+
/**
* Instantiates NEUIo, NEUManager and NEUOverlay instances. Registers keybinds and adds a shutdo