diff --git a/.travis.yml b/.travis.yml index 56ba77b664..6499298b8a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,9 @@ android: - addon-google_apis-google-27 - build-tools-27.0.3 -script: +script: - ./gradlew desktop:dist + - ./gradlew server:dist after_success: - chmod +x upload-build.sh diff --git a/core/src/io/anuke/mindustry/game/ContentDatabase.java b/core/src/io/anuke/mindustry/game/ContentDatabase.java index 97c825964a..4a9934a237 100644 --- a/core/src/io/anuke/mindustry/game/ContentDatabase.java +++ b/core/src/io/anuke/mindustry/game/ContentDatabase.java @@ -4,16 +4,14 @@ import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.ObjectMap; import com.badlogic.gdx.utils.ObjectMap.Entry; import com.badlogic.gdx.utils.ObjectSet; -import io.anuke.mindustry.game.EventType.UnlockEvent; +import io.anuke.mindustry.net.Net; import io.anuke.mindustry.type.ContentType; -import io.anuke.ucore.core.Events; import io.anuke.ucore.core.Settings; +import static io.anuke.mindustry.Vars.*; + public class ContentDatabase{ - /** Maps unlockable type names to a set of unlocked content.*/ - private ObjectMap> unlocked = new ObjectMap<>(); - /** Whether unlockables have changed since the last save.*/ - private boolean dirty; + private ObjectMap sets = new ObjectMap<>(); static{ Settings.setSerializer(ContentType.class, (stream, t) -> stream.writeInt(t.ordinal()), stream -> ContentType.values()[stream.readInt()]); @@ -21,15 +19,7 @@ public class ContentDatabase{ /** Returns whether or not this piece of content is unlocked yet.*/ public boolean isUnlocked(UnlockableContent content){ - if(content.alwaysUnlocked()) return true; - - if(!unlocked.containsKey(content.getContentType())){ - unlocked.put(content.getContentType(), new ObjectSet<>()); - } - - ObjectSet set = unlocked.get(content.getContentType()); - - return set.contains(content.getContentName()); + return rootSet().isUnlocked(content) || currentSet().isUnlocked(content); } /** @@ -40,58 +30,81 @@ public class ContentDatabase{ * @return whether or not this content was newly unlocked. */ public boolean unlockContent(UnlockableContent content){ - if(!content.canBeUnlocked() || content.alwaysUnlocked()) return false; + if(rootSet().isUnlocked(content)) return false; + return currentSet().unlockContent(content); + } - if(!unlocked.containsKey(content.getContentType())){ - unlocked.put(content.getContentType(), new ObjectSet<>()); + private ContentUnlockSet currentSet(){ + //client connected to server: always return the IP-specific set + if(Net.client()){ + return getSet(Net.getLastIP()); + }else if(world.getSector() != null || state.mode.infiniteResources){ //sector-sandbox have shared set + return rootSet(); + }else if(control != null && control.getSaves().getCurrent() != null){ //per-save set + return getSet(String.valueOf(control.getSaves().getCurrent().index)); + }else{ //dedicated server set + return rootSet(); } + } - boolean ret = unlocked.get(content.getContentType()).add(content.getContentName()); + private ContentUnlockSet rootSet(){ + return getSet("root"); + } - //fire unlock event so other classes can use it - if(ret){ - content.onUnlock(); - Events.fire(new UnlockEvent(content)); - dirty = true; + private ContentUnlockSet getSet(String name){ + if(!sets.containsKey(name)){ + sets.put(name, new ContentUnlockSet()); } - - return ret; + return sets.get(name); } /** Returns whether unlockables have changed since the last save.*/ public boolean isDirty(){ - return dirty; + for(ContentUnlockSet set : sets.values()){ + if(set.isDirty()){ + return true; + } + } + return false; } - /** Clears all unlocked content.*/ + /** Clears all unlocked content. Automatically saves.*/ public void reset(){ - unlocked.clear(); - dirty = true; + sets.clear(); + save(); } public void load(){ - ObjectMap> result = Settings.getBinary("content-database", ObjectMap.class, () -> new ObjectMap<>()); + sets.clear(); - for(Entry> entry : result.entries()){ - ObjectSet set = new ObjectSet<>(); - set.addAll(entry.value); - unlocked.put(entry.key, set); + ObjectMap>> result = Settings.getBinary("content-database", ObjectMap.class, () -> new ObjectMap<>()); + + for(Entry>> outer : result.entries()){ + ContentUnlockSet cset = new ContentUnlockSet(); + for (Entry> entry : outer.value.entries()){ + ObjectSet set = new ObjectSet<>(); + set.addAll(entry.value); + cset.getUnlocked().put(entry.key, set); + } + sets.put(outer.key, cset); } - - dirty = false; } public void save(){ + ObjectMap>> output = new ObjectMap<>(); - ObjectMap> write = new ObjectMap<>(); + for(Entry centry : sets.entries()){ + ObjectMap> write = new ObjectMap<>(); - for(Entry> entry : unlocked.entries()){ - write.put(entry.key, entry.value.iterator().toArray()); + for(Entry> entry : centry.value.getUnlocked().entries()){ + write.put(entry.key, entry.value.iterator().toArray()); + } + + output.put(centry.key, write); } - Settings.putBinary("content-database", write); + Settings.putBinary("content-database", output); Settings.save(); - dirty = false; } } diff --git a/core/src/io/anuke/mindustry/game/ContentUnlockSet.java b/core/src/io/anuke/mindustry/game/ContentUnlockSet.java new file mode 100644 index 0000000000..a779c52509 --- /dev/null +++ b/core/src/io/anuke/mindustry/game/ContentUnlockSet.java @@ -0,0 +1,51 @@ +package io.anuke.mindustry.game; + +import com.badlogic.gdx.utils.ObjectMap; +import com.badlogic.gdx.utils.ObjectSet; +import io.anuke.mindustry.game.EventType.UnlockEvent; +import io.anuke.mindustry.type.ContentType; +import io.anuke.ucore.core.Events; + +public class ContentUnlockSet { + private ObjectMap> unlocked = new ObjectMap<>(); + private boolean dirty; + + public boolean isUnlocked(UnlockableContent content){ + if(content.alwaysUnlocked()) return true; + + if(!unlocked.containsKey(content.getContentType())){ + unlocked.put(content.getContentType(), new ObjectSet<>()); + } + + ObjectSet set = unlocked.get(content.getContentType()); + + return set.contains(content.getContentName()); + } + + public boolean unlockContent(UnlockableContent content){ + if(!content.canBeUnlocked() || content.alwaysUnlocked()) return false; + + if(!unlocked.containsKey(content.getContentType())){ + unlocked.put(content.getContentType(), new ObjectSet<>()); + } + + boolean ret = unlocked.get(content.getContentType()).add(content.getContentName()); + + //fire unlock event so other classes can use it + if(ret){ + content.onUnlock(); + Events.fire(new UnlockEvent(content)); + dirty = true; + } + + return ret; + } + + public boolean isDirty() { + return dirty; + } + + public ObjectMap> getUnlocked() { + return unlocked; + } +} diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index a91e1057b2..9755436487 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -31,6 +31,7 @@ public class Net{ private static boolean server; private static boolean active; private static boolean clientLoaded; + private static String lastIP; private static Array packetQueue = new Array<>(); private static ObjectMap, Consumer> clientListeners = new ObjectMap<>(); private static ObjectMap, BiConsumer> serverListeners = new ObjectMap<>(); @@ -79,6 +80,7 @@ public class Net{ * Connect to an address. */ public static void connect(String ip, int port) throws IOException{ + lastIP = ip + ":" + port; if(!active){ clientProvider.connect(ip, port); active = true; @@ -88,6 +90,11 @@ public class Net{ } } + /**Returns the last IP connected to.*/ + public static String getLastIP() { + return lastIP; + } + /** * Host a server at an address. */