From f9cfc8a2b861840ba54413bc4df4b50a87a04ed2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 5 Dec 2020 20:48:56 -0500 Subject: [PATCH] Fixed #3812 / Fixed #3813 --- core/assets/bundles/bundle.properties | 1 + core/src/mindustry/core/Logic.java | 52 ++++++++++++++++++- .../mindustry/ctype/UnlockableContent.java | 4 +- core/src/mindustry/io/TypeIO.java | 16 ++++++ .../mindustry/ui/fragments/HintsFragment.java | 1 + .../world/blocks/storage/CoreBlock.java | 23 ++++---- .../world/blocks/storage/StorageBlock.java | 14 ++--- desktop/src/mindustry/desktop/steam/SNet.java | 7 +-- 8 files changed, 93 insertions(+), 25 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 52feed8ca2..28d9af3072 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1283,6 +1283,7 @@ hint.guardian = [accent]Guardian[] units are armored. Weak ammo such as [accent] hint.coreUpgrade = Cores can be upgraded by [accent]placing higher-tier cores over them[].\n\nPlace a  [accent]Foundation[] core over the  [accent]Shard[] core. Make sure it is free from nearby obstructions. hint.presetLaunch = Gray [accent]landing zone sectors[], such as [accent]Frozen Forest[], can be launched to from anywhere. They do not require capture of nearby territory.\n\n[accent]Numbered sectors[], such as this one, are [accent]optional[]. hint.coreIncinerate = After the core is filled to capacity with an item, any extra items of that type it receives will be [accent]incinerated[]. +hint.coopCampaign = When playing the [accent]co-op campaign[], items that are produced in the current map will also be sent [accent]to your local sectors[].\n\nAny new research done by the host also carries over. item.copper.description = Used in all types of construction and ammunition. item.copper.details = Copper. Abnormally abundant metal on Serpulo. Structurally weak unless reinforced. diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index e468d82d56..bb91fc824e 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -153,6 +153,18 @@ public class Logic implements ApplicationListener{ } }); + //send out items to each client + Events.on(TurnEvent.class, e -> { + if(net.server() && state.isCampaign()){ + int[] out = new int[content.items().size]; + state.getSector().info.production.each((item, stat) -> { + out[item.id] = Math.max(0, (int)(stat.mean * turnDuration / 60)); + }); + + Call.sectorProduced(out); + } + }); + } /** Adds starting items, resets wave time, and sets state to playing. */ @@ -297,8 +309,46 @@ public class Logic implements ApplicationListener{ public static void researched(Content content){ if(!(content instanceof UnlockableContent u)) return; + var node = u.node(); + + //unlock all direct dependencies on client, permanently + while(node != null){ + node.content.unlock(); + node = node.parent; + } + state.rules.researched.add(u.name); - Events.fire(new UnlockEvent(u)); + } + + //called when the remote server runs a turn and produces something + @Remote + public static void sectorProduced(int[] amounts){ + if(!state.isCampaign()) return; + Planet planet = state.rules.sector.planet; + boolean any = false; + + for(Item item : content.items()){ + int am = amounts[item.id]; + if(am > 0){ + int sumMissing = planet.sectors.sum(s -> s.hasBase() ? s.info.storageCapacity - s.info.items.get(item) : 0); + if(sumMissing == 0) continue; + //how much % to add + double percent = Math.min((double)am / sumMissing, 1); + for(Sector sec : planet.sectors){ + if(sec.hasBase()){ + int added = (int)Math.ceil(((sec.info.storageCapacity - sec.info.items.get(item)) * percent)); + sec.info.items.add(item, added); + any = true; + } + } + } + } + + if(any){ + for(Sector sec : planet.sectors){ + sec.saveInfo(); + } + } } @Override diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java index 3ee5ac1ba8..a08dab1b67 100644 --- a/core/src/mindustry/ctype/UnlockableContent.java +++ b/core/src/mindustry/ctype/UnlockableContent.java @@ -117,7 +117,7 @@ public abstract class UnlockableContent extends MappableContent{ /** Makes this piece of content unlocked; if it already unlocked, nothing happens. */ public void unlock(){ - if(!net.client() && !unlocked()){ + if(!unlocked && !alwaysUnlocked){ unlocked = true; Core.settings.put(name + "-unlocked", true); @@ -135,7 +135,7 @@ public abstract class UnlockableContent extends MappableContent{ } public boolean unlocked(){ - if(net != null && net.client()) return alwaysUnlocked || state.rules.researched.contains(name); + if(net != null && net.client()) return unlocked || alwaysUnlocked || state.rules.researched.contains(name); return unlocked || alwaysUnlocked; } diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index 58446a8018..d3172d378e 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -547,6 +547,22 @@ public class TypeIO{ return read.b(new byte[length]); } + public static void writeInts(Writes write, int[] ints){ + write.s((short)ints.length); + for(int i : ints){ + write.i(i); + } + } + + public static int[] readInts(Reads read){ + short length = read.s(); + int[] out = new int[length]; + for(int i = 0; i < length; i++){ + out[i] = read.i(); + } + return out; + } + public static void writeTraceInfo(Writes write, TraceInfo trace){ writeString(write, trace.ip); writeString(write, trace.uuid); diff --git a/core/src/mindustry/ui/fragments/HintsFragment.java b/core/src/mindustry/ui/fragments/HintsFragment.java index 7c7892b8ac..7380457837 100644 --- a/core/src/mindustry/ui/fragments/HintsFragment.java +++ b/core/src/mindustry/ui/fragments/HintsFragment.java @@ -173,6 +173,7 @@ public class HintsFragment extends Fragment{ && SectorPresets.frozenForest.sector.save == null, () -> state.isCampaign() && state.getSector().preset == SectorPresets.frozenForest), coreIncinerate(() -> state.isCampaign() && state.rules.defaultTeam.core() != null && state.rules.defaultTeam.core().items.get(Items.copper) >= state.rules.defaultTeam.core().storageCapacity - 10, () -> false), + coopCampaign(() -> net.client() && state.isCampaign() && SectorPresets.groundZero.sector.hasBase(), () -> false), ; @Nullable diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index e53bd84eff..b310a04b8b 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -6,6 +6,7 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.struct.*; +import arc.util.*; import mindustry.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; @@ -246,17 +247,18 @@ public class CoreBlock extends StorageBlock{ } state.teams.registerCore(this); - storageCapacity = itemCapacity + proximity().sum(e -> isContainer(e) && owns(e) ? e.block.itemCapacity : 0); - proximity.each(e -> isContainer(e) && owns(e), t -> { + storageCapacity = itemCapacity + proximity().sum(e -> owns(e) ? e.block.itemCapacity : 0); + proximity.each(e -> owns(e), t -> { t.items = items; ((StorageBuild)t).linkedCore = this; }); for(Building other : state.teams.cores(team)){ if(other.tile() == tile) continue; - storageCapacity += other.block.itemCapacity + other.proximity().sum(e -> isContainer(e) && owns(other, e) ? e.block.itemCapacity : 0); + storageCapacity += other.block.itemCapacity + other.proximity().sum(e -> owns(e) && owns(other, e) ? e.block.itemCapacity : 0); } + //Team.sharded.core().items.set(Items.surgeAlloy, 12000) if(!world.isGenerating()){ for(Item item : content.items()){ items.set(item, Math.min(items.get(item), storageCapacity)); @@ -303,24 +305,19 @@ public class CoreBlock extends StorageBlock{ Draw.rect("block-select", t.x + offset * p.x, t.y + offset * p.y, i * 90); } }; - if(proximity.contains(e -> isContainer(e) && e.items == items)){ + if(proximity.contains(e -> owns(e) && e.items == items)){ outline.get(this); } - proximity.each(e -> isContainer(e) && e.items == items, outline); + proximity.each(e -> owns(e) && e.items == items, outline); Draw.reset(); } - - public boolean isContainer(Building tile){ - return tile instanceof StorageBuild && (((StorageBuild)tile).linkedCore == this || ((StorageBuild)tile).linkedCore == null); - } - public boolean owns(Building tile){ - return tile instanceof StorageBuild && (((StorageBuild)tile).linkedCore == this || ((StorageBuild)tile).linkedCore == null); + return owns(this, tile); } public boolean owns(Building core, Building tile){ - return tile instanceof StorageBuild && (((StorageBuild)tile).linkedCore == core || ((StorageBuild)tile).linkedCore == null); + return tile instanceof StorageBuild b && (b.linkedCore == core || b.linkedCore == null); } public boolean incinerate(){ @@ -340,7 +337,7 @@ public class CoreBlock extends StorageBlock{ int total = proximity.count(e -> e.items != null && e.items == items); float fract = 1f / total / state.teams.cores(team).size; - proximity.each(e -> isContainer(e) && e.items == items && owns(e), t -> { + proximity.each(e -> owns(e) && e.items == items && owns(e), t -> { StorageBuild ent = (StorageBuild)t; ent.linkedCore = null; ent.items = new ItemModule(); diff --git a/core/src/mindustry/world/blocks/storage/StorageBlock.java b/core/src/mindustry/world/blocks/storage/StorageBlock.java index 7bfda601d1..1ead7b97ab 100644 --- a/core/src/mindustry/world/blocks/storage/StorageBlock.java +++ b/core/src/mindustry/world/blocks/storage/StorageBlock.java @@ -91,14 +91,16 @@ public class StorageBlock extends Block{ @Override public void overwrote(Seq previous){ - for(Building other : previous){ - if(other.items != null){ - items.add(other.items); + //only add prev items when core is not linked + if(linkedCore == null){ + for(Building other : previous){ + if(other.items != null && other.items != items){ + items.add(other.items); + } } - } - //ensure item counts are not too high - items.each((i, a) -> items.set(i, Math.min(a, itemCapacity))); + items.each((i, a) -> items.set(i, Math.min(a, itemCapacity))); + } } @Override diff --git a/desktop/src/mindustry/desktop/steam/SNet.java b/desktop/src/mindustry/desktop/steam/SNet.java index 5d603067f3..03a32297c6 100644 --- a/desktop/src/mindustry/desktop/steam/SNet.java +++ b/desktop/src/mindustry/desktop/steam/SNet.java @@ -31,8 +31,8 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback, final NetProvider provider; final PacketSerializer serializer = new PacketSerializer(); - final ByteBuffer writeBuffer = ByteBuffer.allocateDirect(1024 * 4); - final ByteBuffer readBuffer = ByteBuffer.allocateDirect(1024 * 4); + final ByteBuffer writeBuffer = ByteBuffer.allocateDirect(16384); + final ByteBuffer readBuffer = ByteBuffer.allocateDirect(16384); final CopyOnWriteArrayList connections = new CopyOnWriteArrayList<>(); final IntMap steamConnections = new IntMap<>(); //maps steam ID -> valid net connection @@ -131,9 +131,10 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback, writeBuffer.limit(writeBuffer.capacity()); writeBuffer.position(0); serializer.write(writeBuffer, object); + int length = writeBuffer.position(); writeBuffer.flip(); - snet.sendP2PPacket(currentServer, writeBuffer, mode == SendMode.tcp ? P2PSend.Reliable : P2PSend.UnreliableNoDelay, 0); + snet.sendP2PPacket(currentServer, writeBuffer, mode == SendMode.tcp || length >= 1200 ? P2PSend.Reliable : P2PSend.UnreliableNoDelay, 0); }catch(Exception e){ net.showError(e); }