Workshop implementation progress
This commit is contained in:
@@ -202,7 +202,7 @@ wave.enemy = [lightgray]{0} Enemy Remaining
|
|||||||
loadimage = Load Image
|
loadimage = Load Image
|
||||||
saveimage = Save Image
|
saveimage = Save Image
|
||||||
unknown = Unknown
|
unknown = Unknown
|
||||||
custom = Custom
|
custom = Custom
|
||||||
builtin = Built-In
|
builtin = Built-In
|
||||||
map.delete.confirm = Are you sure you want to delete this map? This action cannot be undone!
|
map.delete.confirm = Are you sure you want to delete this map? This action cannot be undone!
|
||||||
map.random = [accent]Random Map
|
map.random = [accent]Random Map
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
|||||||
batch = new SpriteBatch();
|
batch = new SpriteBatch();
|
||||||
assets = new AssetManager();
|
assets = new AssetManager();
|
||||||
assets.setLoader(Texture.class, "." + mapExtension, new MapPreviewLoader());
|
assets.setLoader(Texture.class, "." + mapExtension, new MapPreviewLoader());
|
||||||
|
assets.load("sprites/error.png", Texture.class);
|
||||||
atlas = TextureAtlas.blankAtlas();
|
atlas = TextureAtlas.blankAtlas();
|
||||||
Vars.net = new Net(platform.getNet());
|
Vars.net = new Net(platform.getNet());
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public class MapLoadDialog extends FloatingDialog{
|
|||||||
for(Map map : maps.all()){
|
for(Map map : maps.all()){
|
||||||
|
|
||||||
TextButton button = new TextButton(map.name(), Styles.togglet);
|
TextButton button = new TextButton(map.name(), Styles.togglet);
|
||||||
button.add(new BorderImage(map.texture, 2f).setScaling(Scaling.fit)).size(16 * 4f);
|
button.add(new BorderImage(map.safeTexture(), 2f).setScaling(Scaling.fit)).size(16 * 4f);
|
||||||
button.getCells().reverse();
|
button.getCells().reverse();
|
||||||
button.clicked(() -> selected = map);
|
button.clicked(() -> selected = map);
|
||||||
button.getLabelCell().grow().left().padLeft(5f);
|
button.getLabelCell().grow().left().padLeft(5f);
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ public class Map implements Comparable<Map>{
|
|||||||
public final FileHandle file;
|
public final FileHandle file;
|
||||||
/** Format version. */
|
/** Format version. */
|
||||||
public final int version;
|
public final int version;
|
||||||
|
/** Whether this map is managed, e.g. downloaded from the Steam workshop.*/
|
||||||
|
public boolean workshop;
|
||||||
/** Map width/height, shorts. */
|
/** Map width/height, shorts. */
|
||||||
public int width, height;
|
public int width, height;
|
||||||
/** Preview texture. */
|
/** Preview texture. */
|
||||||
@@ -57,6 +59,10 @@ public class Map implements Comparable<Map>{
|
|||||||
return Core.settings.getInt("hiscore" + file.nameWithoutExtension(), 0);
|
return Core.settings.getInt("hiscore" + file.nameWithoutExtension(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Texture safeTexture(){
|
||||||
|
return texture == null ? Core.assets.get("sprites/error.png") : texture;
|
||||||
|
}
|
||||||
|
|
||||||
public FileHandle previewFile(){
|
public FileHandle previewFile(){
|
||||||
return Vars.mapPreviewDirectory.child(file.nameWithoutExtension() + ".png");
|
return Vars.mapPreviewDirectory.child(file.nameWithoutExtension() + ".png");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ public class Maps{
|
|||||||
|
|
||||||
/** Load all maps. Should be called at application start. */
|
/** Load all maps. Should be called at application start. */
|
||||||
public void load(){
|
public void load(){
|
||||||
|
//defaults; must work
|
||||||
try{
|
try{
|
||||||
for(String name : defaultMapNames){
|
for(String name : defaultMapNames){
|
||||||
FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension);
|
FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension);
|
||||||
@@ -90,7 +91,27 @@ public class Maps{
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadCustomMaps();
|
//custom
|
||||||
|
for(FileHandle file : customMapDirectory.list()){
|
||||||
|
try{
|
||||||
|
if(file.extension().equalsIgnoreCase(mapExtension)){
|
||||||
|
loadMap(file, true);
|
||||||
|
}
|
||||||
|
}catch(Exception e){
|
||||||
|
Log.err("Failed to load custom map file '{0}'!", file);
|
||||||
|
Log.err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//workshop
|
||||||
|
for(FileHandle file : platform.getExternalMaps()){
|
||||||
|
try{
|
||||||
|
loadMap(file, false).workshop = true;
|
||||||
|
}catch(Exception e){
|
||||||
|
Log.err("Failed to load workshop map file '{0}'!", file);
|
||||||
|
Log.err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reload(){
|
public void reload(){
|
||||||
@@ -174,14 +195,6 @@ public class Maps{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a legacy map by converting it to a non-legacy map and pasting it in a temp directory.
|
|
||||||
* Should be followed up by {@link #importMap(FileHandle)} .*/
|
|
||||||
public Map makeLegacyMap(FileHandle file) throws IOException{
|
|
||||||
FileHandle dst = tmpDirectory.child("conversion_map." + mapExtension);
|
|
||||||
LegacyMapIO.convertMap(file, dst);
|
|
||||||
return MapIO.createMap(dst, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Import a map, then save it. This updates all values and stored data necessary. */
|
/** Import a map, then save it. This updates all values and stored data necessary. */
|
||||||
public void importMap(FileHandle file) throws IOException{
|
public void importMap(FileHandle file) throws IOException{
|
||||||
FileHandle dest = findFile();
|
FileHandle dest = findFile();
|
||||||
@@ -203,7 +216,6 @@ public class Maps{
|
|||||||
if(error[0] != null){
|
if(error[0] != null){
|
||||||
throw new IOException(error[0]);
|
throw new IOException(error[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Attempts to run the following code;
|
/** Attempts to run the following code;
|
||||||
@@ -312,9 +324,11 @@ public class Maps{
|
|||||||
public void loadPreviews(){
|
public void loadPreviews(){
|
||||||
|
|
||||||
for(Map map : maps){
|
for(Map map : maps){
|
||||||
|
Log.info("Generating preview for {0}", map.name());
|
||||||
//try to load preview
|
//try to load preview
|
||||||
if(map.previewFile().exists()){
|
if(map.previewFile().exists()){
|
||||||
//this may fail, but calls createNewPreview
|
Log.info("> exists");
|
||||||
|
//this may fail, but calls queueNewPreview
|
||||||
Core.assets.load(new AssetDescriptor<>(map.previewFile().path() + "." + mapExtension, Texture.class, new MapPreviewParameter(map))).loaded = t -> map.texture = (Texture)t;
|
Core.assets.load(new AssetDescriptor<>(map.previewFile().path() + "." + mapExtension, Texture.class, new MapPreviewParameter(map))).loaded = t -> map.texture = (Texture)t;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
@@ -324,6 +338,7 @@ public class Maps{
|
|||||||
queueNewPreview(map);
|
queueNewPreview(map);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
Log.info("> doesn't exist, queuing");
|
||||||
queueNewPreview(map);
|
queueNewPreview(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,7 +347,8 @@ public class Maps{
|
|||||||
private void createAllPreviews(){
|
private void createAllPreviews(){
|
||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
for(Map map : previewList){
|
for(Map map : previewList){
|
||||||
createNewPreview(map, e -> Core.app.post(() -> map.texture = new Texture("sprites/error.png")));
|
Log.info("> > GEN NEW preview for {0}", map.name());
|
||||||
|
createNewPreview(map, e -> Core.app.post(() -> map.texture = Core.assets.get("sprites/error.png")));
|
||||||
}
|
}
|
||||||
previewList.clear();
|
previewList.clear();
|
||||||
});
|
});
|
||||||
@@ -407,16 +423,4 @@ public class Maps{
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadCustomMaps(){
|
|
||||||
for(FileHandle file : customMapDirectory.list()){
|
|
||||||
try{
|
|
||||||
if(file.extension().equalsIgnoreCase(mapExtension)){
|
|
||||||
loadMap(file, true);
|
|
||||||
}
|
|
||||||
}catch(Exception e){
|
|
||||||
Log.err("Failed to load custom map file '{0}'!", file);
|
|
||||||
Log.err(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -25,8 +25,8 @@ public class CrashSender{
|
|||||||
try{
|
try{
|
||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
|
|
||||||
//don't create crash logs for me (anuke) or custom builds, as it's expected
|
//don't create crash logs for custom builds, as it's expected
|
||||||
if(System.getProperty("user.name").equals("anuke") || Version.build == -1) return;
|
if(Version.build == -1) return;
|
||||||
|
|
||||||
//attempt to load version regardless
|
//attempt to load version regardless
|
||||||
if(Version.number == 0){
|
if(Version.number == 0){
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class CustomGameDialog extends FloatingDialog{
|
|||||||
maps.row();
|
maps.row();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageButton image = new ImageButton(new TextureRegion(map.texture), Styles.cleari);
|
ImageButton image = new ImageButton(new TextureRegion(map.safeTexture()), Styles.cleari);
|
||||||
image.margin(5);
|
image.margin(5);
|
||||||
image.top();
|
image.top();
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ public class CustomGameDialog extends FloatingDialog{
|
|||||||
image.add(img).size(images);
|
image.add(img).size(images);
|
||||||
|
|
||||||
|
|
||||||
BorderImage border = new BorderImage(map.texture, 3f);
|
BorderImage border = new BorderImage(map.safeTexture(), 3f);
|
||||||
border.setScaling(Scaling.fit);
|
border.setScaling(Scaling.fit);
|
||||||
image.replaceImage(border);
|
image.replaceImage(border);
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class MapPlayDialog extends FloatingDialog{
|
|||||||
cont.row();
|
cont.row();
|
||||||
cont.addImageTextButton("$customize", Icon.toolsSmall, () -> dialog.show(rules, () -> rules = map.applyRules(selectedGamemode))).width(230);
|
cont.addImageTextButton("$customize", Icon.toolsSmall, () -> dialog.show(rules, () -> rules = map.applyRules(selectedGamemode))).width(230);
|
||||||
cont.row();
|
cont.row();
|
||||||
cont.add(new BorderImage(map.texture, 3f)).size(mobile && !Core.graphics.isPortrait() ? 150f : 250f).get().setScaling(Scaling.fit);
|
cont.add(new BorderImage(map.safeTexture(), 3f)).size(mobile && !Core.graphics.isPortrait() ? 150f : 250f).get().setScaling(Scaling.fit);
|
||||||
//only maps with survival are valid for high scores
|
//only maps with survival are valid for high scores
|
||||||
if(Gamemode.survival.valid(map)){
|
if(Gamemode.survival.valid(map)){
|
||||||
cont.row();
|
cont.row();
|
||||||
|
|||||||
@@ -143,9 +143,9 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
button.row();
|
button.row();
|
||||||
button.addImage().growX().pad(4).color(Pal.gray);
|
button.addImage().growX().pad(4).color(Pal.gray);
|
||||||
button.row();
|
button.row();
|
||||||
button.stack(new Image(map.texture).setScaling(Scaling.fit), new BorderImage(map.texture).setScaling(Scaling.fit)).size(mapsize - 20f);
|
button.stack(new Image(map.safeTexture()).setScaling(Scaling.fit), new BorderImage(map.safeTexture()).setScaling(Scaling.fit)).size(mapsize - 20f);
|
||||||
button.row();
|
button.row();
|
||||||
button.add(map.custom ? "$custom" : "$builtin").color(Color.gray).padTop(3);
|
button.add(map.custom ? "$custom" : map.workshop ? "$workshop" : "$builtin").color(Color.gray).padTop(3);
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,7 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
float mapsize = Core.graphics.isPortrait() ? 160f : 300f;
|
float mapsize = Core.graphics.isPortrait() ? 160f : 300f;
|
||||||
Table table = dialog.cont;
|
Table table = dialog.cont;
|
||||||
|
|
||||||
table.stack(new Image(map.texture).setScaling(Scaling.fit), new BorderImage(map.texture).setScaling(Scaling.fit)).size(mapsize);
|
table.stack(new Image(map.safeTexture()).setScaling(Scaling.fit), new BorderImage(map.safeTexture()).setScaling(Scaling.fit)).size(mapsize);
|
||||||
|
|
||||||
table.table(Styles.black, desc -> {
|
table.table(Styles.black, desc -> {
|
||||||
desc.top();
|
desc.top();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import io.anuke.arc.Files.*;
|
|||||||
import io.anuke.arc.backends.sdl.*;
|
import io.anuke.arc.backends.sdl.*;
|
||||||
import io.anuke.arc.backends.sdl.jni.*;
|
import io.anuke.arc.backends.sdl.jni.*;
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.files.*;
|
||||||
import io.anuke.arc.function.*;
|
import io.anuke.arc.function.*;
|
||||||
import io.anuke.arc.input.*;
|
import io.anuke.arc.input.*;
|
||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
@@ -48,11 +49,12 @@ public class DesktopLauncher extends ClientLauncher{
|
|||||||
setWindowIcon(FileType.Internal, "icons/icon_64.png");
|
setWindowIcon(FileType.Internal, "icons/icon_64.png");
|
||||||
}});
|
}});
|
||||||
}catch(Throwable e){
|
}catch(Throwable e){
|
||||||
DesktopLauncher.handleCrash(e);
|
handleCrash(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DesktopLauncher(String[] args){
|
public DesktopLauncher(String[] args){
|
||||||
|
Log.setUseColors(false);
|
||||||
Version.init();
|
Version.init();
|
||||||
boolean useSteam = Version.modifier.equals("steam");
|
boolean useSteam = Version.modifier.equals("steam");
|
||||||
testMobile = Array.with(args).contains("-testMobile");
|
testMobile = Array.with(args).contains("-testMobile");
|
||||||
@@ -72,6 +74,16 @@ public class DesktopLauncher extends ClientLauncher{
|
|||||||
|
|
||||||
if(useSteam){
|
if(useSteam){
|
||||||
if(showConsole){
|
if(showConsole){
|
||||||
|
StringBuilder base = new StringBuilder();
|
||||||
|
Log.setLogger(new LogHandler(){
|
||||||
|
@Override
|
||||||
|
public void print(String text, Object... args){
|
||||||
|
String out = Log.format(text, false, args);
|
||||||
|
|
||||||
|
base.append(out).append("\n");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Events.on(ClientLoadEvent.class, event -> {
|
Events.on(ClientLoadEvent.class, event -> {
|
||||||
Label[] label = {null};
|
Label[] label = {null};
|
||||||
boolean[] visible = {false};
|
boolean[] visible = {false};
|
||||||
@@ -86,6 +98,7 @@ public class DesktopLauncher extends ClientLauncher{
|
|||||||
t.toFront();
|
t.toFront();
|
||||||
});
|
});
|
||||||
t.table(Styles.black3, f -> label[0] = f.add("").get()).visible(() -> visible[0]);
|
t.table(Styles.black3, f -> label[0] = f.add("").get()).visible(() -> visible[0]);
|
||||||
|
label[0].getText().append(base);
|
||||||
});
|
});
|
||||||
|
|
||||||
Log.setLogger(new LogHandler(){
|
Log.setLogger(new LogHandler(){
|
||||||
@@ -177,12 +190,18 @@ public class DesktopLauncher extends ClientLauncher{
|
|||||||
boolean fbgp = badGPU;
|
boolean fbgp = badGPU;
|
||||||
|
|
||||||
CrashSender.send(e, file -> {
|
CrashSender.send(e, file -> {
|
||||||
|
Throwable cause = Strings.getFinalCause(e);
|
||||||
if(!fbgp){
|
if(!fbgp){
|
||||||
dialog.accept(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + (e.getMessage() == null ? "" : "\n" + e.getMessage())));
|
dialog.accept(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + cause.getClass().getSimpleName().replace("Exception", "") + (cause.getMessage() == null ? "" : ":\n" + cause.getMessage())));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Array<FileHandle> getExternalMaps(){
|
||||||
|
return !steam ? super.getExternalMaps() : SVars.workshop.getMapFiles();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NetProvider getNet(){
|
public NetProvider getNet(){
|
||||||
return steam ? SVars.net : new ArcNetImpl();
|
return steam ? SVars.net : new ArcNetImpl();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.codedisaster.steamworks.*;
|
|||||||
import com.codedisaster.steamworks.SteamRemoteStorage.*;
|
import com.codedisaster.steamworks.SteamRemoteStorage.*;
|
||||||
import com.codedisaster.steamworks.SteamUGC.*;
|
import com.codedisaster.steamworks.SteamUGC.*;
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.files.*;
|
import io.anuke.arc.files.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
@@ -18,17 +19,23 @@ public class SWorkshop implements SteamUGCCallback{
|
|||||||
public final SteamUGC ugc = new SteamUGC(this);
|
public final SteamUGC ugc = new SteamUGC(this);
|
||||||
|
|
||||||
private Map lastMap;
|
private Map lastMap;
|
||||||
|
private Array<FileHandle> mapFiles;
|
||||||
|
|
||||||
public SWorkshop(){
|
public SWorkshop(){
|
||||||
int items = ugc.getNumSubscribedItems();
|
int items = ugc.getNumSubscribedItems();
|
||||||
SteamPublishedFileID[] ids = new SteamPublishedFileID[items];
|
SteamPublishedFileID[] ids = new SteamPublishedFileID[items];
|
||||||
|
ItemInstallInfo info = new ItemInstallInfo();
|
||||||
ugc.getSubscribedItems(ids);
|
ugc.getSubscribedItems(ids);
|
||||||
for(int i = 0; i < items; i++){
|
mapFiles = Array.with(ids).map(f -> {
|
||||||
SteamPublishedFileID id = ids[i];
|
ugc.getItemInstallInfo(f, info);
|
||||||
ItemInstallInfo info = new ItemInstallInfo();
|
return new FileHandle(info.getFolder());
|
||||||
ugc.getItemInstallInfo(id, info);
|
}).select(f -> f.list().length > 0).map(f -> f.list()[0]);
|
||||||
|
|
||||||
}
|
Log.info("Fetching {0} subscribed maps.", items);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<FileHandle> getMapFiles(){
|
||||||
|
return mapFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void publishMap(Map map){
|
public void publishMap(Map map){
|
||||||
|
|||||||
Reference in New Issue
Block a user