aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorBlueWeabo <ilia.iliev2005@gmail.com>2023-02-26 13:16:07 +0200
committerGitHub <noreply@github.com>2023-02-26 12:16:07 +0100
commitb8d1ecf8b9b6348304392d09e4490d473dbb120d (patch)
tree1cdc59a1b660510fe2abd40686b2abed8b0ab40f /src/main/java
parentebd7df3a1ddba9105df008d44ab046d159279628 (diff)
downloadGT5-Unofficial-b8d1ecf8b9b6348304392d09e4490d473dbb120d.tar.gz
GT5-Unofficial-b8d1ecf8b9b6348304392d09e4490d473dbb120d.tar.bz2
GT5-Unofficial-b8d1ecf8b9b6348304392d09e4490d473dbb120d.zip
Add a completely new system for late/endgame content (#1754)
* basic work * typo fixes * make an enum folder * location enums * space project manager * implement the space project teams * commands * move things around and new things * upgrade work * requirement work * if possible use an upgrades values * cleanup * more helpers in command * fix AOOBE * fix world saved data * builder for requirements * add command autocomplete * fix command npe * mark world saved data dirty * switch to saving to json string. this is fine * fix npe * fix files not saving correctly. serialization * spotless * part 1 of fixing json saving * working json file saving * rename fields * full implementation of SP_Upgrade * fixes * cleanup * texture prep * documentation part 1 * documentation part 2 and rework of json saving * fix the missed conversions * set texture when copying * more interface usage and fixes * rework saving. * Added rudimentary NEI handler for projects * Revert "Added rudimentary NEI handler for projects" This reverts commit 6d8210e25b27fee7dc1865d1afa91708a8d9b875. * address NPEs * some textures * higher quality textures, put in the moon as a temp texture * add a check to create a team if one smt weird happens * command work * add ability to localize the space bodies * Added disabled button and toggle button * Added possibility to not render the original stacksize of item stacks in NEI * Added NEI handler * Fixes item count on tooltip always rendering as 1 * Fix refactor * 5 new body textures * fix misspelled texture name --------- Co-authored-by: minecraft7771 <maxim235@gmx.de>
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/gregtech/GT_Mod.java4
-rw-r--r--src/main/java/gregtech/api/gui/modularui/GT_UITextures.java4
-rw-r--r--src/main/java/gregtech/api/util/GT_Recipe.java146
-rw-r--r--src/main/java/gregtech/common/GT_Proxy.java2
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/SpaceProjectManager.java278
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/SpaceProjectWorldSavedData.java275
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/base/SP_Requirements.java77
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/base/SP_Upgrade.java347
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/base/SpaceProject.java440
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/commands/SPM_Command.java233
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/commands/SP_Command.java120
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/enums/JsonVariables.java22
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/enums/SolarSystem.java96
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/enums/SpaceBodyType.java17
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/enums/StarType.java32
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/enums/UpgradeStatus.java11
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/interfaces/ISpaceBody.java37
-rw-r--r--src/main/java/gregtech/common/misc/spaceprojects/interfaces/ISpaceProject.java430
-rw-r--r--src/main/java/gregtech/nei/GT_NEI_DefaultHandler.java72
19 files changed, 2637 insertions, 6 deletions
diff --git a/src/main/java/gregtech/GT_Mod.java b/src/main/java/gregtech/GT_Mod.java
index 7a8236c7b3..6622277cb0 100644
--- a/src/main/java/gregtech/GT_Mod.java
+++ b/src/main/java/gregtech/GT_Mod.java
@@ -83,6 +83,8 @@ import gregtech.common.covers.GT_Cover_FacadeAE;
import gregtech.common.entities.GT_Entity_Arrow;
import gregtech.common.entities.GT_Entity_Arrow_Potion;
import gregtech.common.misc.GT_Command;
+import gregtech.common.misc.spaceprojects.commands.SPM_Command;
+import gregtech.common.misc.spaceprojects.commands.SP_Command;
import gregtech.common.tileentities.storage.GT_MetaTileEntity_DigitalChestBase;
import gregtech.crossmod.Waila;
import gregtech.loaders.load.GT_CoverBehaviorLoader;
@@ -708,6 +710,8 @@ public class GT_Mod implements IGT_Mod {
}
aEvent.registerServerCommand(new GT_Command());
+ aEvent.registerServerCommand(new SP_Command());
+ aEvent.registerServerCommand(new SPM_Command());
// Sets a new Machine Block Update Thread everytime a world is loaded
GT_Runnable_MachineBlockUpdate.initExecutorService();
}
diff --git a/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java b/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java
index a480178002..d3b353e1ec 100644
--- a/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java
+++ b/src/main/java/gregtech/api/gui/modularui/GT_UITextures.java
@@ -190,8 +190,12 @@ public class GT_UITextures {
.adaptableTexture(MODID, "gui/tab/title_angular_%s", 28, 28, 4);
public static final UITexture BUTTON_STANDARD = AdaptableUITexture.of(MODID, "gui/button/standard", 18, 18, 1);
+ public static final UITexture BUTTON_STANDARD_DISABLED = AdaptableUITexture
+ .of(MODID, "gui/button/standard_disabled", 18, 18, 1);
public static final UITexture BUTTON_STANDARD_TOGGLE = AdaptableUITexture
.of(MODID, "gui/button/standard_toggle", 18, 18, 1);
+ public static final UITexture BUTTON_STANDARD_TOGGLE_DISABLED = AdaptableUITexture
+ .of(MODID, "gui/button/standard_toggle_disabled", 18, 18, 1);
public static final UITexture BUTTON_COVER_NORMAL = UITexture.fullImage(MODID, "gui/button/cover_normal");
public static final UITexture BUTTON_COVER_NORMAL_HOVERED = UITexture
.fullImage(MODID, "gui/button/cover_normal_hovered");
diff --git a/src/main/java/gregtech/api/util/GT_Recipe.java b/src/main/java/gregtech/api/util/GT_Recipe.java
index 506ab9ba6b..3b7f64aae8 100644
--- a/src/main/java/gregtech/api/util/GT_Recipe.java
+++ b/src/main/java/gregtech/api/util/GT_Recipe.java
@@ -3,6 +3,7 @@ package gregtech.api.util;
import static gregtech.api.enums.GT_Values.*;
import static gregtech.api.util.GT_Utility.formatNumbers;
import static net.minecraft.util.EnumChatFormatting.GRAY;
+import static net.minecraft.util.StatCollector.translateToLocal;
import java.awt.*;
import java.util.*;
@@ -29,6 +30,8 @@ import net.minecraftforge.fluids.IFluidContainerItem;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
+import appeng.util.ReadableNumberConverter;
+import codechicken.lib.gui.GuiDraw;
import codechicken.nei.PositionedStack;
import com.gtnewhorizons.modularui.api.GlStateManager;
@@ -65,6 +68,9 @@ import gregtech.api.objects.ItemData;
import gregtech.api.objects.MaterialStack;
import gregtech.api.util.extensions.ArrayExt;
import gregtech.common.gui.modularui.UIHelper;
+import gregtech.common.items.GT_FluidDisplayItem;
+import gregtech.common.misc.spaceprojects.SpaceProjectManager;
+import gregtech.common.misc.spaceprojects.interfaces.ISpaceProject;
import gregtech.common.power.EUPower;
import gregtech.common.power.Power;
import gregtech.common.power.UnspecifiedEUPower;
@@ -1748,6 +1754,131 @@ public class GT_Recipe implements Comparable<GT_Recipe> {
false,
true);
+ public static class GT_FakeSpaceProjectRecipe extends GT_Recipe {
+
+ public final String projectName;
+
+ public GT_FakeSpaceProjectRecipe(boolean aOptimize, ItemStack[] aInputs, FluidStack[] aFluidInputs,
+ int aDuration, int aEUt, int aSpecialValue, String projectName) {
+ super(aOptimize, aInputs, null, null, null, aFluidInputs, null, aDuration, aEUt, aSpecialValue);
+ this.projectName = projectName;
+ }
+ }
+
+ public static final GT_Recipe_Map sFakeSpaceProjectRecipes = new GT_Recipe_Map(
+ new HashSet<>(20),
+ "gt.recipe.fakespaceprojects",
+ "Space Projects",
+ null,
+ RES_PATH_GUI + "basicmachines/Default",
+ 12,
+ 0,
+ 0,
+ 0,
+ 1,
+ translateToLocal("gt.specialvalue.stages") + " ",
+ 1,
+ "",
+ false,
+ true) {
+
+ IDrawable projectTexture;
+
+ @Override
+ public ModularWindow.Builder createNEITemplate(IItemHandlerModifiable itemInputsInventory,
+ IItemHandlerModifiable itemOutputsInventory, IItemHandlerModifiable specialSlotInventory,
+ IItemHandlerModifiable fluidInputsInventory, IItemHandlerModifiable fluidOutputsInventory,
+ Supplier<Float> progressSupplier, Pos2d windowOffset) {
+ ModularWindow.Builder builder = super.createNEITemplate(
+ itemInputsInventory,
+ itemOutputsInventory,
+ specialSlotInventory,
+ fluidInputsInventory,
+ fluidOutputsInventory,
+ progressSupplier,
+ windowOffset);
+ addRecipeSpecificDrawable(
+ builder,
+ windowOffset,
+ () -> projectTexture,
+ new Pos2d(124, 28),
+ new Size(18, 18));
+ return builder;
+ }
+
+ @Override
+ public List<Pos2d> getItemInputPositions(int itemInputCount) {
+ return UIHelper.getGridPositions(itemInputCount, 16, 28, 3);
+ }
+
+ @Override
+ public List<Pos2d> getFluidInputPositions(int fluidInputCount) {
+ return UIHelper.getGridPositions(fluidInputCount, 88, 28, 1);
+ }
+
+ @Override
+ protected List<String> handleNEIItemInputTooltip(List<String> currentTip,
+ GT_NEI_DefaultHandler.FixedPositionedStack pStack) {
+ super.handleNEIItemOutputTooltip(currentTip, pStack);
+ if (pStack.item != null && pStack.item.getItem() instanceof GT_FluidDisplayItem) return currentTip;
+ currentTip.add(GRAY + translateToLocal("Item Count: ") + formatNumbers(pStack.realStackSize));
+ return currentTip;
+ }
+
+ @Override
+ public void drawNEIOverlays(GT_NEI_DefaultHandler.CachedDefaultRecipe neiCachedRecipe) {
+ for (PositionedStack stack : neiCachedRecipe.mInputs) {
+ if (stack instanceof GT_NEI_DefaultHandler.FixedPositionedStack && stack.item != null
+ && !(stack.item.getItem() instanceof GT_FluidDisplayItem)) {
+ int stackSize = ((GT_NEI_DefaultHandler.FixedPositionedStack) stack).realStackSize;
+ String displayString;
+ if (stack.item.stackSize > 9999) {
+ displayString = ReadableNumberConverter.INSTANCE.toWideReadableForm(stackSize);
+ } else {
+ displayString = String.valueOf(stackSize);
+ }
+ drawNEIOverlayText(displayString, stack, 0xffffff, 0.5f, true, Alignment.BottomRight);
+ }
+ }
+ if (neiCachedRecipe.mRecipe instanceof GT_FakeSpaceProjectRecipe) {
+ ISpaceProject project = SpaceProjectManager
+ .getProject(((GT_FakeSpaceProjectRecipe) neiCachedRecipe.mRecipe).projectName);
+ if (project != null) {
+ projectTexture = project.getTexture();
+ GuiDraw.drawStringC(
+ EnumChatFormatting.BOLD + project.getLocalizedName(),
+ 85,
+ 0,
+ 0x404040,
+ false);
+ }
+ }
+ }
+
+ @Override
+ public void addProgressBarUI(ModularWindow.Builder builder, Supplier<Float> progressSupplier,
+ Pos2d windowOffset) {
+ int bar1Width = 17;
+ int bar2Width = 18;
+ builder.widget(
+ new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_1, 17)
+ .setDirection(ProgressBar.Direction.RIGHT)
+ .setProgress(
+ () -> progressSupplier.get() * ((float) (bar1Width + bar2Width) / bar1Width))
+ .setSynced(false, false).setPos(new Pos2d(70, 28).add(windowOffset))
+ .setSize(bar1Width, 72));
+ builder.widget(
+ new ProgressBar().setTexture(GT_UITextures.PROGRESSBAR_ASSEMBLY_LINE_2, 18)
+ .setDirection(ProgressBar.Direction.RIGHT)
+ .setProgress(
+ () -> (progressSupplier.get() - ((float) bar1Width / (bar1Width + bar2Width)))
+ * ((float) (bar1Width + bar2Width) / bar2Width))
+ .setSynced(false, false).setPos(new Pos2d(106, 28).add(windowOffset))
+ .setSize(bar2Width, 72));
+ }
+ }.useModularUI(true).setRenderRealStackSizes(false).setUsualFluidInputCount(4).setNEIBackgroundOffset(2, 23)
+ .setLogoPos(152, 83);
+
public static class TranscendentPlasmaMixerRecipeMap extends GT_Recipe_Map {
public TranscendentPlasmaMixerRecipeMap(Collection<GT_Recipe> aRecipeList, String aUnlocalizedName,
@@ -2624,6 +2755,11 @@ public class GT_Recipe implements Comparable<GT_Recipe> {
public boolean useComparatorForNEI;
/**
+ * Whether to render the actual size of stacks or a size of 1.
+ */
+ public boolean renderRealStackSizes = true;
+
+ /**
* Initialises a new type of Recipe Handler.
*
* @param aRecipeList a List you specify as Recipe List. Usually just an ArrayList with a
@@ -2712,6 +2848,11 @@ public class GT_Recipe implements Comparable<GT_Recipe> {
return this;
}
+ public GT_Recipe_Map setRenderRealStackSizes(boolean renderRealStackSizes) {
+ this.renderRealStackSizes = renderRealStackSizes;
+ return this;
+ }
+
public GT_Recipe_Map useModularUI(boolean use) {
this.useModularUI = use;
return this;
@@ -3362,6 +3503,11 @@ public class GT_Recipe implements Comparable<GT_Recipe> {
builder.widget(new DrawableWidget().setDrawable(logo).setSize(logoSize).setPos(logoPos.add(windowOffset)));
}
+ public void addRecipeSpecificDrawable(ModularWindow.Builder builder, Pos2d windowOffset,
+ Supplier<IDrawable> supplier, Pos2d pos, Size size) {
+ builder.widget(new DrawableWidget().setDrawable(supplier).setSize(size).setPos(pos.add(windowOffset)));
+ }
+
/**
* Overriding this method allows custom NEI stack placement
*/
diff --git a/src/main/java/gregtech/common/GT_Proxy.java b/src/main/java/gregtech/common/GT_Proxy.java
index ccc04f171e..3f50da2230 100644
--- a/src/main/java/gregtech/common/GT_Proxy.java
+++ b/src/main/java/gregtech/common/GT_Proxy.java
@@ -141,6 +141,7 @@ import gregtech.common.entities.GT_Entity_Arrow;
import gregtech.common.items.GT_MetaGenerated_Item_98;
import gregtech.common.items.GT_MetaGenerated_Tool_01;
import gregtech.common.misc.GlobalEnergyWorldSavedData;
+import gregtech.common.misc.spaceprojects.SpaceProjectWorldSavedData;
public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler, IGlobalWirelessEnergy {
@@ -1051,6 +1052,7 @@ public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler, IG
}
MinecraftForge.EVENT_BUS.register(new GlobalEnergyWorldSavedData(""));
+ MinecraftForge.EVENT_BUS.register(new SpaceProjectWorldSavedData());
// IC2 Hazmat
addFullHazmatToIC2Item("hazmatHelmet");
diff --git a/src/main/java/gregtech/common/misc/spaceprojects/SpaceProjectManager.java b/src/main/java/gregtech/common/misc/spaceprojects/SpaceProjectManager.java
new file mode 100644
index 0000000000..81c7fac375
--- /dev/null
+++ b/src/main/java/gregtech/common/misc/spaceprojects/SpaceProjectManager.java
@@ -0,0 +1,278 @@
+package gregtech.common.misc.spaceprojects;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import net.minecraft.server.MinecraftServer;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+import gregtech.api.util.GT_Recipe;
+import gregtech.common.misc.spaceprojects.interfaces.ISpaceBody;
+import gregtech.common.misc.spaceprojects.interfaces.ISpaceProject;
+
+/**
+ * @author BlueWeabo
+ */
+public class SpaceProjectManager {
+
+ /**
+ * Do not use! Only meant to be used in SpaceProjectWorldSavedData.java
+ */
+ public static Map<UUID, Map<Pair<ISpaceBody, String>, ISpaceProject>> spaceTeamProjects = new HashMap<>();
+ /**
+ * Do not use! Only meant to be used in SpaceProjectWorldSavedData.java Stores a Players UUID to the Leader UUID,
+ * players in lone groups give back their own UUID.
+ */
+ public static Map<UUID, UUID> spaceTeams = new HashMap<>();
+
+ /**
+ * Stores all the locations to a hash map to be accessed easier instead of through an enum
+ */
+ private static final HashMap<String, ISpaceBody> spaceLocations = new HashMap<>();
+
+ /**
+ * Stores all projects that have been made. Only adds them to this map if {@link #addProject(ISpaceProject)} has
+ * been used
+ */
+ private static final Map<String, ISpaceProject> spaceProjects = new HashMap<>();
+
+ // #region Space Project Team Helper methods
+
+ /**
+ * Used to get a specific project of the team dependent on the location and the project's name
+ */
+ public static ISpaceProject getTeamProject(UUID member, ISpaceBody location, String projectName) {
+ Map<Pair<ISpaceBody, String>, ISpaceProject> map = spaceTeamProjects.get(getLeader(member));
+ if (map == null) {
+ return null;
+ }
+ return map.get(Pair.of(location, projectName));
+ }
+
+ /**
+ * Makes a new Map for the teams if they don't have one. Adds a project to the team's project map.
+ *
+ * @param member Member of the team.
+ * @param location The location of where the project will belong to.
+ * @param projectName The name of the project being added.
+ * @param project Project which will be added to the team.
+ * @return Returns true when a project was added to the map of the player. Returns false otherwise.
+ */
+ public static boolean addTeamProject(UUID member, ISpaceBody location, String projectName, ISpaceProject project) {
+ if (!spaceTeamProjects.containsKey(getLeader(member)) || spaceTeamProjects.get(getLeader(member)) == null) {
+ spaceTeamProjects.put(getLeader(member), new HashMap<Pair<ISpaceBody, String>, ISpaceProject>());
+ }
+
+ Map<Pair<ISpaceBody, String>, ISpaceProject> map = spaceTeamProjects.get(getLeader(member));
+ if (map.containsKey(Pair.of(location, projectName))) {
+ return false;
+ }
+
+ project.setProjectLocation(location);
+ map.put(Pair.of(location, projectName), project);
+ SpaceProjectWorldSavedData.INSTANCE.markDirty();
+ return true;
+ }
+
+ /**
+ * Check whether a team has a project or not
+ *
+ * @param member Member of the team
+ * @param project The project, which you are checking for. This only compares the internal names of the project.
+ * @return True if the team has said project, false otherwise
+ */
+ public static boolean teamHasProject(UUID member, ISpaceProject project) {
+ Map<Pair<ISpaceBody, String>, ISpaceProject> map = spaceTeamProjects.get(getLeader(member));
+ if (map == null) {
+ return false;
+ }
+
+ return map.containsValue(project);
+ }
+
+ /**
+ * Used to handle when 2 players want to join together in a team. Player A can join player B's team. If player C
+ * gets an invite from A, C will join player B's team.
+ *
+ * @param teamMember Member which is joining the teamLeader
+ * @param teamLeader Leader of the party
+ */
+ public static void putInTeam(UUID teamMember, UUID teamLeader) {
+ if (teamMember.equals(teamLeader)) {
+ spaceTeams.put(teamMember, teamLeader);
+ } else if (!spaceTeams.get(teamLeader).equals(teamLeader)) {
+ putInTeam(teamMember, spaceTeams.get(teamLeader));
+ } else {
+ spaceTeams.put(teamMember, teamLeader);
+ }
+
+ SpaceProjectWorldSavedData.INSTANCE.markDirty();
+ }
+
+ /**
+ * Used to give back the UUID of the team leader.
+ *
+ * @return The UUID of the team leader.
+ */
+ public static UUID getLeader(UUID teamMember) {
+ checkOrCreateTeam(teamMember);
+ return spaceTeams.get(teamMember);
+ }
+
+ /**
+ * Used the multiblocks to check whether a given player has a team or not. If they don't have a team create one
+ * where they are their own leader.
+ *
+ * @param teamMember Member to check for.
+ */
+ public static void checkOrCreateTeam(UUID teamMember) {
+ if (spaceTeams.containsKey(teamMember)) {
+ return;
+ }
+
+ spaceTeams.put(teamMember, teamMember);
+ SpaceProjectWorldSavedData.INSTANCE.markDirty();
+ }
+
+ /**
+ * Will give back all the projects a team has made or is making.
+ *
+ * @param member UUID of the team member, used to find the leader of the team.
+ * @return All the projects a team has.
+ */
+ public static Collection<ISpaceProject> getTeamSpaceProjects(UUID member) {
+ Map<Pair<ISpaceBody, String>, ISpaceProject> map = spaceTeamProjects.get(getLeader(member));
+ if (map == null) {
+ return null;
+ }
+
+ return map.values();
+ }
+
+ /**
+ * Getting the project of a Team or a new copy.
+ *
+ * @param member UUID of the team member, which is used to find the team leader.
+ * @param projectName The name of the project, which needs to be found.
+ * @param location The location at which the project is found at.
+ * @return the project that the team has or a copy of a project.
+ */
+ public static ISpaceProject getTeamProjectOrCopy(UUID member, String projectName, ISpaceBody location) {
+ Map<Pair<ISpaceBody, String>, ISpaceProject> map = spaceTeamProjects.get(getLeader(member));
+ if (map == null) {
+ return getProject(projectName);
+ }
+
+ return map.getOrDefault(Pair.of(location, projectName), getProject(projectName));
+ }
+
+ // #endregion
+
+ // #region Project Helper methods
+
+ /**
+ * Used to add projects to the internal map.
+ *
+ * @param project Newly created project.
+ */
+ public static void addProject(ISpaceProject project) {
+ spaceProjects.put(project.getProjectName(), project);
+ GT_Recipe.GT_Recipe_Map.sFakeSpaceProjectRecipes.add(
+ new GT_Recipe.GT_Recipe_Map.GT_FakeSpaceProjectRecipe(
+ false,
+ project.getTotalItemsCost(),
+ project.getTotalFluidsCost(),
+ project.getProjectBuildTime(),
+ (int) project.getProjectVoltage(),
+ project.getTotalStages(),
+ project.getProjectName()));
+ }
+
+ /**
+ * @param projectName Internal name of the project.
+ * @return a copy of the stored project.
+ */
+ public static ISpaceProject getProject(String projectName) {
+ ISpaceProject tProject = spaceProjects.get(projectName);
+ return tProject != null ? tProject.copy() : null;
+ }
+
+ /**
+ * Should only be used for GUIs!
+ *
+ * @return The Map that the projects are stored at.
+ */
+ public static Map<String, ISpaceProject> getProjectsMap() {
+ return spaceProjects;
+ }
+
+ /**
+ * Should only be used for GUIs!
+ *
+ * @return A Collection of all the projects contained in the map.
+ */
+ public static Collection<ISpaceProject> getAllProjects() {
+ return spaceProjects.values();
+ }
+
+ // #endregion
+
+ // #region Location Helper methods
+
+ /**
+ * Adds a location to the internal map. For it to be used later
+ *
+ * @param location to add to the internal map
+ */
+ public static void addLocation(ISpaceBody location) {
+ spaceLocations.put(location.getName(), location);
+ }
+
+ /**
+ *
+ * @return a Collection of all locations, which have been registered.
+ */
+ public static Collection<ISpaceBody> getLocations() {
+ return spaceLocations.values();
+ }
+
+ /**
+ *
+ * @return a Collection fo all location names, which have been registered
+ */
+ public static Collection<String> getLocationNames() {
+ return spaceLocations.keySet();
+ }
+
+ /**
+ *
+ * @param locationName Name used to search for the location
+ * @return The location, which has been registered with said name
+ */
+ public static ISpaceBody getLocation(String locationName) {
+ return spaceLocations.get(locationName);
+ }
+
+ // #endregion
+
+ // #region General Helper methods
+
+ /**
+ * Gets the UUID using the player's username
+ */
+ public static UUID getPlayerUUIDFromName(String playerName) {
+ return MinecraftServer.getServer().func_152358_ax().func_152655_a(playerName).getId();
+ }
+
+ /**
+ * Gets the player's name using their UUID
+ */
+ public static String getPlayerNameFromUUID(UUID playerUUID) {
+ return MinecraftServer.getServer().func_152358_ax().func_152652_a(playerUUID).getName();
+ }
+
+ // #endregion
+}
diff --git a/src/main/java/gregtech/common/misc/spaceprojects/SpaceProjectWorldSavedData.java b/src/main/java/gregtech/common/misc/spaceprojects/SpaceProjectWorldSavedData.java
new file mode 100644
index 0000000000..6dc80db3ec
--- /dev/null
+++ b/src/main/java/gregtech/common/misc/spaceprojects/SpaceProjectWorldSavedData.java
@@ -0,0 +1,275 @@
+package gregtech.common.misc.spaceprojects;
+
+import static gregtech.common.misc.spaceprojects.SpaceProjectManager.spaceTeamProjects;
+import static gregtech.common.misc.spaceprojects.SpaceProjectManager.spaceTeams;
+import static gregtech.common.misc.spaceprojects.enums.JsonVariables.*;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldSavedData;
+import net.minecraft.world.storage.MapStorage;
+import net.minecraftforge.event.world.WorldEvent;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+import cpw.mods.fml.common.eventhandler.SubscribeEvent;
+import gregtech.common.misc.spaceprojects.enums.SolarSystem;
+import gregtech.common.misc.spaceprojects.interfaces.ISpaceBody;
+import gregtech.common.misc.spaceprojects.interfaces.ISpaceProject;
+import gregtech.common.misc.spaceprojects.interfaces.ISpaceProject.ISP_Upgrade;
+
+/**
+ * This class is used so that I can write and read to a json file before the world is opened. On server starting is too
+ * late for this as the data stored in the files is needed before entities load their nbt data
+ *
+ * @author BlueWeabo
+ */
+public class SpaceProjectWorldSavedData extends WorldSavedData {
+
+ public static SpaceProjectWorldSavedData INSTANCE;
+
+ private static final Gson GSON_SPACE_PROJECT = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization()
+ .registerTypeAdapter(spaceTeamProjects.getClass(), new SpaceTeamProjectsMapAdapter())
+ .registerTypeAdapter(Map.class, new SpaceTeamProjectsMapAdapter())
+ .registerTypeAdapter(Pair.of((ISpaceBody) SolarSystem.Ariel, "").getClass(), new PairAdapter())
+ .registerTypeAdapter(Pair.class, new PairAdapter())
+ .registerTypeAdapter(ISpaceProject.class, new SpaceProjectAdapter())
+ .registerTypeAdapter(ISP_Upgrade.class, new SP_UpgradeAdapter())
+ .registerTypeHierarchyAdapter(ISpaceProject.class, new SpaceProjectAdapter())
+ .registerTypeHierarchyAdapter(ISP_Upgrade.class, new SP_UpgradeAdapter()).create();
+ private static final Gson GSON_TEAMS = new GsonBuilder().serializeNulls().create();
+
+ private static final String DATA_NAME = "GT_SpaceProjectData";
+
+ private static final String SPACE_TEAM_PROJECTS_JSON = "spaceTeamProject.json";
+
+ private static final String SPACE_TEAMS_JSON = "spaceTeams.json";
+
+ private static File spaceTeamsFile;
+ private static File teamProjectsFile;
+
+ public SpaceProjectWorldSavedData() {
+ super(DATA_NAME);
+ }
+
+ public SpaceProjectWorldSavedData(String aData) {
+ super(aData);
+ }
+
+ @Override
+ public void readFromNBT(NBTTagCompound aNBT) {
+ try (JsonReader reader = new JsonReader(new FileReader(teamProjectsFile))) {
+ spaceTeamProjects = GSON_SPACE_PROJECT.fromJson(reader, spaceTeamProjects.getClass());
+ } catch (Exception e) {
+ System.out.print("FAILED TO LOAD: " + SPACE_TEAM_PROJECTS_JSON);
+ e.printStackTrace();
+ }
+
+ try (JsonReader reader = new JsonReader(new FileReader(spaceTeamsFile))) {
+ spaceTeams = GSON_TEAMS.fromJson(reader, spaceTeams.getClass());
+ } catch (Exception e) {
+ System.out.print("FAILED TO LOAD: " + SPACE_TEAMS_JSON);
+ e.printStackTrace();
+ }
+
+ if (spaceTeams == null) {
+ spaceTeams = new HashMap<>();
+ }
+ }
+
+ @Override
+ public void writeToNBT(NBTTagCompound aNBT) {
+ try (JsonWriter writer = new JsonWriter(new FileWriter(teamProjectsFile))) {
+ GSON_SPACE_PROJECT.toJson(spaceTeamProjects, spaceTeamProjects.getClass(), writer);
+ } catch (Exception ex) {
+ System.out.print("FAILED TO SAVE: " + SPACE_TEAM_PROJECTS_JSON);
+ ex.printStackTrace();
+ }
+
+ try (JsonWriter writer = new JsonWriter(new FileWriter(spaceTeamsFile))) {
+ GSON_TEAMS.toJson(spaceTeams, spaceTeams.getClass(), writer);
+ } catch (Exception ex) {
+ System.out.print("FAILED TO SAVE: " + SPACE_TEAMS_JSON);
+ ex.printStackTrace();
+ }
+ }
+
+ private static void loadInstance(World aWorld) {
+ spaceTeamProjects.clear();
+ spaceTeams.clear();
+ spaceTeamsFile = new File(aWorld.getSaveHandler().getWorldDirectory(), SPACE_TEAMS_JSON);
+ teamProjectsFile = new File(aWorld.getSaveHandler().getWorldDirectory(), SPACE_TEAM_PROJECTS_JSON);
+ MapStorage tStorage = aWorld.mapStorage;
+ INSTANCE = (SpaceProjectWorldSavedData) tStorage.loadData(SpaceProjectWorldSavedData.class, DATA_NAME);
+ if (INSTANCE == null) {
+ INSTANCE = new SpaceProjectWorldSavedData();
+ tStorage.setData(DATA_NAME, INSTANCE);
+ }
+ INSTANCE.markDirty();
+ }
+
+ @SubscribeEvent
+ public void onWorldLoad(WorldEvent.Load aEvent) {
+ if (!aEvent.world.isRemote && aEvent.world.provider.dimensionId == 0) {
+ loadInstance(aEvent.world);
+ }
+ }
+
+ private static class PairAdapter
+ implements JsonSerializer<Pair<ISpaceBody, String>>, JsonDeserializer<Pair<ISpaceBody, String>> {
+
+ @Override
+ public JsonElement serialize(Pair<ISpaceBody, String> src, Type typeOfSrc, JsonSerializationContext context) {
+ JsonObject pair = new JsonObject();
+ pair.addProperty(PAIR_LEFT, src.getLeft().getName());
+ pair.addProperty(PAIR_RIGHT, src.getRight());
+ return pair;
+ }
+
+ @Override
+ public Pair<ISpaceBody, String> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ throws JsonParseException {
+ Pair<ISpaceBody, String> pair = null;
+ if (json.isJsonObject()) {
+ JsonObject obj = json.getAsJsonObject();
+ pair = Pair.of(
+ SpaceProjectManager.getLocation(obj.get(PAIR_L