diff --git a/patchwork.md b/patchwork.md index f7be787fe..aead31369 100644 --- a/patchwork.md +++ b/patchwork.md @@ -611,4 +611,11 @@ Lua changes. Fix mounts being usable after a disk is ejected ``` -Reverted a lot of code style changes made by Zundrel, so the diffs are huge. \ No newline at end of file +Reverted a lot of code style changes made by Zundrel, so the diffs are huge. + +``` +b90611b4b4c176ec1c80df002cc4ac36aa0c4dc8 + +Preserve registration order of upgrades +``` +Again, a huge diff because of code style changes. diff --git a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java index 072bc47f6..6704ac02b 100644 --- a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java @@ -3,61 +3,59 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import dan200.computercraft.api.pocket.IPocketUpgrade; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenCustomHashMap; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Util; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.*; -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.pocket.IPocketUpgrade; -import dan200.computercraft.shared.util.InventoryUtil; - -import net.minecraft.item.ItemStack; - -public final class PocketUpgrades { +public final class PocketUpgrades +{ private static final Map upgrades = new HashMap<>(); - private static final IdentityHashMap upgradeOwners = new IdentityHashMap<>(); + private static final Map upgradeOwners = new Object2ObjectLinkedOpenCustomHashMap<>( Util.identityHashStrategy() ); private PocketUpgrades() {} - public static synchronized void register(@Nonnull IPocketUpgrade upgrade) { - Objects.requireNonNull(upgrade, "upgrade cannot be null"); + public static synchronized void register( @Nonnull IPocketUpgrade upgrade ) + { + Objects.requireNonNull( upgrade, "upgrade cannot be null" ); - String id = upgrade.getUpgradeID() - .toString(); - IPocketUpgrade existing = upgrades.get(id); - if (existing != null) { - throw new IllegalStateException("Error registering '" + upgrade.getUnlocalisedAdjective() + " pocket computer'. UpgradeID '" + id + "' is " + - "already registered by '" + existing.getUnlocalisedAdjective() + " pocket computer'"); + String id = upgrade.getUpgradeID().toString(); + IPocketUpgrade existing = upgrades.get( id ); + if( existing != null ) + { + throw new IllegalStateException( "Error registering '" + upgrade.getUnlocalisedAdjective() + " pocket computer'. UpgradeID '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " pocket computer'" ); } - upgrades.put(id, upgrade); + upgrades.put( id, upgrade ); + + // Infer the mod id by the identifier of the upgrade. This is not how the forge api works, so it may break peripheral mods using the api. + // TODO: get the mod id of the mod that is currently being loaded. + ModContainer mc = FabricLoader.getInstance().getModContainer(upgrade.getUpgradeID().getNamespace()).orElseGet(null); + if( mc != null && mc.getMetadata().getId() != null ) upgradeOwners.put( upgrade, mc.getMetadata().getId() ); } - public static IPocketUpgrade get(String id) { + public static IPocketUpgrade get( String id ) + { // Fix a typo in the advanced modem upgrade's name. I'm sorry, I realise this is horrible. - if (id.equals("computercraft:advanved_modem")) { - id = "computercraft:advanced_modem"; - } + if( id.equals( "computercraft:advanved_modem" ) ) id = "computercraft:advanced_modem"; - return upgrades.get(id); + return upgrades.get( id ); } - public static IPocketUpgrade get(@Nonnull ItemStack stack) { - if (stack.isEmpty()) { - return null; - } + public static IPocketUpgrade get( @Nonnull ItemStack stack ) + { + if( stack.isEmpty() ) return null; - for (IPocketUpgrade upgrade : upgrades.values()) { + for( IPocketUpgrade upgrade : upgrades.values() ) + { ItemStack craftingStack = upgrade.getCraftingItem(); if( !craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && upgrade.isItemSuitable( stack ) ) { @@ -69,19 +67,22 @@ public final class PocketUpgrades { } @Nullable - public static String getOwner(IPocketUpgrade upgrade) { - return upgradeOwners.get(upgrade); + public static String getOwner( IPocketUpgrade upgrade ) + { + return upgradeOwners.get( upgrade ); } - public static Iterable getVanillaUpgrades() { + public static Iterable getVanillaUpgrades() + { List vanilla = new ArrayList<>(); - vanilla.add(ComputerCraftRegistry.PocketUpgrades.wirelessModemNormal); - vanilla.add(ComputerCraftRegistry.PocketUpgrades.wirelessModemAdvanced); - vanilla.add(ComputerCraftRegistry.PocketUpgrades.speaker); + vanilla.add( ComputerCraftRegistry.PocketUpgrades.wirelessModemNormal ); + vanilla.add( ComputerCraftRegistry.PocketUpgrades.wirelessModemAdvanced ); + vanilla.add( ComputerCraftRegistry.PocketUpgrades.speaker ); return vanilla; } - public static Iterable getUpgrades() { - return Collections.unmodifiableCollection(upgrades.values()); + public static Iterable getUpgrades() + { + return Collections.unmodifiableCollection( upgrades.values() ); } -} +} \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index 31d3686f7..5153367ca 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -3,9 +3,15 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.turtle.ITurtleUpgrade; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import net.minecraft.item.ItemStack; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Arrays; import java.util.HashMap; import java.util.IdentityHashMap; @@ -13,86 +19,72 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Stream; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; +public final class TurtleUpgrades +{ + private static class Wrapper + { + final ITurtleUpgrade upgrade; + final String id; + final String modId; + boolean enabled; -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.shared.computer.core.ComputerFamily; + Wrapper( ITurtleUpgrade upgrade ) + { + this.upgrade = upgrade; + this.id = upgrade.getUpgradeID() + .toString(); + // TODO This should be the mod id of the mod the peripheral comes from + this.modId = ComputerCraft.MOD_ID; + this.enabled = true; + } + } -import net.minecraft.item.ItemStack; + private static ITurtleUpgrade[] vanilla; -public final class TurtleUpgrades { private static final Map upgrades = new HashMap<>(); private static final IdentityHashMap wrappers = new IdentityHashMap<>(); - private static ITurtleUpgrade[] vanilla; private static boolean needsRebuild; + private TurtleUpgrades() {} - public static void register(@Nonnull ITurtleUpgrade upgrade) { - Objects.requireNonNull(upgrade, "upgrade cannot be null"); + public static void register( @Nonnull ITurtleUpgrade upgrade ) + { + Objects.requireNonNull( upgrade, "upgrade cannot be null" ); rebuild(); - Wrapper wrapper = new Wrapper(upgrade); + Wrapper wrapper = new Wrapper( upgrade ); String id = wrapper.id; - ITurtleUpgrade existing = upgrades.get(id); - if (existing != null) { - throw new IllegalStateException("Error registering '" + upgrade.getUnlocalisedAdjective() + " Turtle'. Upgrade ID '" + id + "' is already " + - "registered by '" + existing.getUnlocalisedAdjective() + " Turtle'"); + ITurtleUpgrade existing = upgrades.get( id ); + if( existing != null ) + { + throw new IllegalStateException( "Error registering '" + upgrade.getUnlocalisedAdjective() + " Turtle'. Upgrade ID '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); } - upgrades.put(id, upgrade); - wrappers.put(upgrade, wrapper); - } - - /** - * Rebuild the cache of turtle upgrades. This is done before querying the cache or registering new upgrades. - */ - private static void rebuild() { - if (!needsRebuild) { - return; - } - - upgrades.clear(); - for (Wrapper wrapper : wrappers.values()) { - if (!wrapper.enabled) { - continue; - } - - ITurtleUpgrade existing = upgrades.get(wrapper.id); - if (existing != null) { - ComputerCraft.log.error("Error registering '" + wrapper.upgrade.getUnlocalisedAdjective() + " Turtle'." + " Upgrade ID '" + wrapper.id + - "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'"); - continue; - } - - upgrades.put(wrapper.id, wrapper.upgrade); - } - - needsRebuild = false; + upgrades.put( id, upgrade ); + wrappers.put( upgrade, wrapper ); } @Nullable - public static ITurtleUpgrade get(String id) { + public static ITurtleUpgrade get( String id ) + { rebuild(); - return upgrades.get(id); + return upgrades.get( id ); } @Nullable - public static String getOwner(@Nonnull ITurtleUpgrade upgrade) { - Wrapper wrapper = wrappers.get(upgrade); + public static String getOwner( @Nonnull ITurtleUpgrade upgrade ) + { + Wrapper wrapper = wrappers.get( upgrade ); return wrapper != null ? wrapper.modId : null; } - public static ITurtleUpgrade get(@Nonnull ItemStack stack) { - if (stack.isEmpty()) { - return null; - } + public static ITurtleUpgrade get( @Nonnull ItemStack stack ) + { + if( stack.isEmpty() ) return null; - for (Wrapper wrapper : wrappers.values()) { - if (!wrapper.enabled) { - continue; - } + for( Wrapper wrapper : wrappers.values() ) + { + if( !wrapper.enabled ) continue; ItemStack craftingStack = wrapper.upgrade.getCraftingItem(); if( !craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && wrapper.upgrade.isItemSuitable( stack ) ) @@ -104,8 +96,10 @@ public final class TurtleUpgrades { return null; } - public static Stream getVanillaUpgrades() { - if (vanilla == null) { + public static Stream getVanillaUpgrades() + { + if( vanilla == null ) + { vanilla = new ITurtleUpgrade[] { // ComputerCraft upgrades ComputerCraftRegistry.TurtleUpgrades.wirelessModemNormal, @@ -119,64 +113,69 @@ public final class TurtleUpgrades { ComputerCraftRegistry.TurtleUpgrades.diamondShovel, ComputerCraftRegistry.TurtleUpgrades.diamondHoe, ComputerCraftRegistry.TurtleUpgrades.craftingTable, - - ComputerCraftRegistry.TurtleUpgrades.netheritePickaxe, }; } - return Arrays.stream(vanilla) - .filter(x -> x != null && wrappers.get(x).enabled); + return Arrays.stream( vanilla ).filter( x -> x != null && wrappers.get( x ).enabled ); } - public static Stream getUpgrades() { - return wrappers.values() - .stream() - .filter(x -> x.enabled) - .map(x -> x.upgrade); + public static Stream getUpgrades() + { + return wrappers.values().stream().filter( x -> x.enabled ).map( x -> x.upgrade ); } - public static boolean suitableForFamily(ComputerFamily family, ITurtleUpgrade upgrade) { + public static boolean suitableForFamily( ComputerFamily family, ITurtleUpgrade upgrade ) + { return true; } - public static void enable(ITurtleUpgrade upgrade) { - Wrapper wrapper = wrappers.get(upgrade); - if (wrapper.enabled) { - return; + /** + * Rebuild the cache of turtle upgrades. This is done before querying the cache or registering new upgrades. + */ + private static void rebuild() + { + if( !needsRebuild ) return; + + upgrades.clear(); + for( Wrapper wrapper : wrappers.values() ) + { + if( !wrapper.enabled ) continue; + + ITurtleUpgrade existing = upgrades.get( wrapper.id ); + if( existing != null ) + { + ComputerCraft.log.error( "Error registering '" + wrapper.upgrade.getUnlocalisedAdjective() + " Turtle'." + + " Upgrade ID '" + wrapper.id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); + continue; + } + + upgrades.put( wrapper.id, wrapper.upgrade ); } + needsRebuild = false; + } + + public static void enable( ITurtleUpgrade upgrade ) + { + Wrapper wrapper = wrappers.get( upgrade ); + if( wrapper.enabled ) return; + wrapper.enabled = true; needsRebuild = true; } - public static void disable(ITurtleUpgrade upgrade) { - Wrapper wrapper = wrappers.get(upgrade); - if (!wrapper.enabled) { - return; - } + public static void disable( ITurtleUpgrade upgrade ) + { + Wrapper wrapper = wrappers.get( upgrade ); + if( !wrapper.enabled ) return; wrapper.enabled = false; - upgrades.remove(wrapper.id); + upgrades.remove( wrapper.id ); } - public static void remove(ITurtleUpgrade upgrade) { - wrappers.remove(upgrade); + public static void remove( ITurtleUpgrade upgrade ) + { + wrappers.remove( upgrade ); needsRebuild = true; } - - private static class Wrapper { - final ITurtleUpgrade upgrade; - final String id; - final String modId; - boolean enabled; - - Wrapper(ITurtleUpgrade upgrade) { - this.upgrade = upgrade; - this.id = upgrade.getUpgradeID() - .toString(); - // TODO This should be the mod id of the mod the peripheral comes from - this.modId = ComputerCraft.MOD_ID; - this.enabled = true; - } - } -} +} \ No newline at end of file