v0.8.0: added an update notification service
This commit is contained in:
parent
2e533b74db
commit
2138ad24ec
|
@ -28,6 +28,7 @@ import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONTokener;
|
import org.json.JSONTokener;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -35,7 +36,6 @@ import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PushbackInputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -45,6 +45,8 @@ import java.util.zip.GZIPOutputStream;
|
||||||
public class Bundle {
|
public class Bundle {
|
||||||
|
|
||||||
private static final String CLASS_NAME = "__className";
|
private static final String CLASS_NAME = "__className";
|
||||||
|
|
||||||
|
public static final String DEFAULT_KEY = "key";
|
||||||
|
|
||||||
private static HashMap<String,String> aliases = new HashMap<>();
|
private static HashMap<String,String> aliases = new HashMap<>();
|
||||||
|
|
||||||
|
@ -223,6 +225,25 @@ public class Bundle {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Bundle[] getBundleArray(){
|
||||||
|
return getBundleArray( DEFAULT_KEY );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bundle[] getBundleArray( String key ){
|
||||||
|
try {
|
||||||
|
JSONArray array = data.getJSONArray( key );
|
||||||
|
int length = array.length();
|
||||||
|
Bundle[] result = new Bundle[length];
|
||||||
|
for (int i=0; i < length; i++) {
|
||||||
|
result[i] = new Bundle( array.getJSONObject( i ) );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
Game.reportException(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Collection<Bundlable> getCollection( String key ) {
|
public Collection<Bundlable> getCollection( String key ) {
|
||||||
|
|
||||||
|
@ -410,22 +431,32 @@ public class Bundle {
|
||||||
public static Bundle read( InputStream stream ) throws IOException {
|
public static Bundle read( InputStream stream ) throws IOException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
BufferedReader reader;
|
if (!stream.markSupported()){
|
||||||
|
stream = new BufferedInputStream( stream, 2 );
|
||||||
|
}
|
||||||
|
|
||||||
//determines if we're reading a regular, or compressed file
|
//determines if we're reading a regular, or compressed file
|
||||||
PushbackInputStream pb = new PushbackInputStream( stream, 2 );
|
stream.mark( 2 );
|
||||||
byte[] header = new byte[2];
|
byte[] header = new byte[2];
|
||||||
pb.unread(header, 0, pb.read(header));
|
stream.read( header );
|
||||||
|
stream.reset();
|
||||||
|
|
||||||
//GZIP header is 0x1f8b
|
//GZIP header is 0x1f8b
|
||||||
if( header[ 0 ] == (byte) 0x1f && header[ 1 ] == (byte) 0x8b )
|
if( header[ 0 ] == (byte) 0x1f && header[ 1 ] == (byte) 0x8b ) {
|
||||||
reader = new BufferedReader( new InputStreamReader( new GZIPInputStream( pb, GZIP_BUFFER ) ) );
|
stream = new GZIPInputStream( stream, GZIP_BUFFER );
|
||||||
else
|
}
|
||||||
reader = new BufferedReader( new InputStreamReader( pb ) );
|
|
||||||
|
|
||||||
JSONObject json = (JSONObject)new JSONTokener( reader.readLine() ).nextValue();
|
//cannot just tokenize the stream directly as that constructor doesn't exist on Android
|
||||||
|
BufferedReader reader = new BufferedReader( new InputStreamReader( stream ));
|
||||||
|
Object json = new JSONTokener( reader.readLine() ).nextValue();
|
||||||
reader.close();
|
reader.close();
|
||||||
|
|
||||||
return new Bundle( json );
|
//if the data is an array, put it in a fresh object with the default key
|
||||||
|
if (json instanceof JSONArray){
|
||||||
|
json = new JSONObject().put( DEFAULT_KEY, json );
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Bundle( (JSONObject) json );
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Game.reportException(e);
|
Game.reportException(e);
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
|
|
|
@ -28,6 +28,8 @@ public abstract class PlatformSupport {
|
||||||
public abstract void updateDisplaySize();
|
public abstract void updateDisplaySize();
|
||||||
|
|
||||||
public abstract void updateSystemUI();
|
public abstract void updateSystemUI();
|
||||||
|
|
||||||
|
public abstract boolean connectedToUnmeteredNetwork();
|
||||||
|
|
||||||
//FIXME this is currently used because no platform-agnostic text input has been implemented.
|
//FIXME this is currently used because no platform-agnostic text input has been implemented.
|
||||||
//should look into doing that using either plain openGL or Libgdx's libraries
|
//should look into doing that using either plain openGL or Libgdx's libraries
|
||||||
|
|
|
@ -25,6 +25,9 @@ android {
|
||||||
debug {
|
debug {
|
||||||
applicationIdSuffix ".indev"
|
applicationIdSuffix ".indev"
|
||||||
versionNameSuffix '-INDEV'
|
versionNameSuffix '-INDEV'
|
||||||
|
dependencies {
|
||||||
|
debugImplementation project(':services:updates:debugUpdates')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
|
|
||||||
|
@ -35,6 +38,10 @@ android {
|
||||||
shrinkResources true
|
shrinkResources true
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
releaseImplementation project(':services:updates:githubUpdates')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
<uses-feature android:glEsVersion="0x00020000"/>
|
<uses-feature android:glEsVersion="0x00020000"/>
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
<!-- Note that the game doesn't truly support small screen resolutions,
|
<!-- Note that the game doesn't truly support small screen resolutions,
|
||||||
it instead forces downscaling to work on these displays.-->
|
it instead forces downscaling to work on these displays.-->
|
||||||
|
|
|
@ -32,6 +32,8 @@ import com.badlogic.gdx.backends.android.AndroidApplication;
|
||||||
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
|
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
|
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
|
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.services.updates.UpdateImpl;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates;
|
||||||
import com.watabou.noosa.Game;
|
import com.watabou.noosa.Game;
|
||||||
import com.watabou.utils.FileUtils;
|
import com.watabou.utils.FileUtils;
|
||||||
|
|
||||||
|
@ -58,9 +60,13 @@ public class AndroidGame extends AndroidApplication {
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
Game.versionCode = 0;
|
Game.versionCode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (UpdateImpl.supportsUpdates()){
|
||||||
|
Updates.service = UpdateImpl.getUpdateService();
|
||||||
|
}
|
||||||
|
|
||||||
FileUtils.setDefaultFileProperties( Files.FileType.Local, "" );
|
FileUtils.setDefaultFileProperties( Files.FileType.Local, "" );
|
||||||
|
|
||||||
// grab preferences directly using our instance first
|
// grab preferences directly using our instance first
|
||||||
// so that we don't need to rely on Gdx.app, which isn't initialized yet.
|
// so that we don't need to rely on Gdx.app, which isn't initialized yet.
|
||||||
SPDSettings.set(instance.getPreferences("ShatteredPixelDungeon"));
|
SPDSettings.set(instance.getPreferences("ShatteredPixelDungeon"));
|
||||||
|
@ -91,7 +97,7 @@ public class AndroidGame extends AndroidApplication {
|
||||||
initialize(new ShatteredPixelDungeon(support), config);
|
initialize(new ShatteredPixelDungeon(support), config);
|
||||||
|
|
||||||
view = (GLSurfaceView)graphics.getView();
|
view = (GLSurfaceView)graphics.getView();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -22,7 +22,10 @@
|
||||||
package com.shatteredpixel.shatteredpixeldungeon.android;
|
package com.shatteredpixel.shatteredpixeldungeon.android;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
@ -140,6 +143,23 @@ public class AndroidPlatformSupport extends PlatformSupport {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public boolean connectedToUnmeteredNetwork() {
|
||||||
|
//Returns true if using unmetered connection, use shortcut method if available
|
||||||
|
ConnectivityManager cm = (ConnectivityManager) AndroidGame.instance.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
|
||||||
|
return !cm.isActiveNetworkMetered();
|
||||||
|
} else {
|
||||||
|
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
|
||||||
|
return activeNetwork != null && activeNetwork.isConnectedOrConnecting() &&
|
||||||
|
(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI
|
||||||
|
|| activeNetwork.getType() == ConnectivityManager.TYPE_WIMAX
|
||||||
|
|| activeNetwork.getType() == ConnectivityManager.TYPE_BLUETOOTH
|
||||||
|
|| activeNetwork.getType() == ConnectivityManager.TYPE_ETHERNET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void promptTextInput(final String title, final String hintText, final int maxLen, final boolean multiLine, final String posTxt, final String negTxt, final TextCallback callback) {
|
public void promptTextInput(final String title, final String hintText, final int maxLen, final boolean multiLine, final String posTxt, final String negTxt, final TextCallback callback) {
|
||||||
Game.runOnRenderThread( new Callback() {
|
Game.runOnRenderThread( new Callback() {
|
||||||
|
|
|
@ -5,4 +5,6 @@ sourceCompatibility = targetCompatibility = appJavaCompatibility
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(':SPD-classes')
|
api project(':SPD-classes')
|
||||||
|
//TODO might be nice to remove this, should decide
|
||||||
|
implementation project(':services')
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.ui.LanguageButton;
|
import com.shatteredpixel.shatteredpixeldungeon.ui.LanguageButton;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.ui.PrefsButton;
|
import com.shatteredpixel.shatteredpixeldungeon.ui.PrefsButton;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
|
import com.shatteredpixel.shatteredpixeldungeon.ui.StyledButton;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.ui.UpdateNotification;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
|
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndStartGame;
|
import com.shatteredpixel.shatteredpixeldungeon.windows.WndStartGame;
|
||||||
import com.watabou.glwrap.Blending;
|
import com.watabou.glwrap.Blending;
|
||||||
|
@ -225,6 +226,10 @@ public class TitleScene extends PixelScene {
|
||||||
btnExit.setPos( w - btnExit.width(), 0 );
|
btnExit.setPos( w - btnExit.width(), 0 );
|
||||||
add( btnExit );
|
add( btnExit );
|
||||||
|
|
||||||
|
UpdateNotification updInfo = new UpdateNotification();
|
||||||
|
updInfo.setRect(4, h-BTN_HEIGHT, updInfo.reqWidth() + 6, BTN_HEIGHT-4);
|
||||||
|
add(updInfo);
|
||||||
|
|
||||||
fadeIn();
|
fadeIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 Evan Debenham
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
|
||||||
|
|
||||||
|
public class Updates {
|
||||||
|
|
||||||
|
public static UpdateService service;
|
||||||
|
|
||||||
|
public static boolean supportsUpdates(){
|
||||||
|
return service != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean updateChecked = false;
|
||||||
|
|
||||||
|
public static void checkForUpdate(){
|
||||||
|
if (!supportsUpdates() || updateChecked) return;
|
||||||
|
service.checkForUpdate(new UpdateService.UpdateResultCallback() {
|
||||||
|
@Override
|
||||||
|
public void onUpdateAvailable(AvailableUpdateData update) {
|
||||||
|
updateChecked = true;
|
||||||
|
updateData = update;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNoUpdateFound() {
|
||||||
|
updateChecked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionFailed() {
|
||||||
|
updateChecked = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void launchUpdate( AvailableUpdateData data ){
|
||||||
|
service.initializeUpdate( data );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AvailableUpdateData updateData = null;
|
||||||
|
|
||||||
|
public static boolean updateAvailable(){
|
||||||
|
return updateData != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AvailableUpdateData updateData(){
|
||||||
|
return updateData;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 Evan Debenham
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.ui;
|
||||||
|
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.Chrome;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.services.updates.AvailableUpdateData;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions;
|
||||||
|
import com.watabou.noosa.Game;
|
||||||
|
|
||||||
|
public class UpdateNotification extends StyledButton {
|
||||||
|
|
||||||
|
private static AvailableUpdateData update;
|
||||||
|
|
||||||
|
public UpdateNotification(){
|
||||||
|
super( Chrome.Type.GREY_BUTTON_TR, Messages.get(UpdateNotification.class, "title") );
|
||||||
|
textColor( Window.SHPX_COLOR );
|
||||||
|
visible = false;
|
||||||
|
Updates.checkForUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
super.update();
|
||||||
|
|
||||||
|
if (Updates.updateAvailable()){
|
||||||
|
bg.alpha((float) (0.7f + Math.sin(Game.timeTotal*2)*0.3f));
|
||||||
|
text.alpha((float) (0.7f + Math.sin(Game.timeTotal*2)*0.3f));
|
||||||
|
visible = true;
|
||||||
|
} else {
|
||||||
|
visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onClick() {
|
||||||
|
update = Updates.updateData();
|
||||||
|
ShatteredPixelDungeon.scene().addToFront( new WndUpdate() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WndUpdate extends WndOptions {
|
||||||
|
|
||||||
|
public WndUpdate(){
|
||||||
|
super(
|
||||||
|
update.versionName == null ? Messages.get(WndUpdate.class,"title") : Messages.get(WndUpdate.class,"versioned_title", update.versionName),
|
||||||
|
update.desc == null ? Messages.get(WndUpdate.class,"desc") : update.desc,
|
||||||
|
Messages.get(WndUpdate.class,"button"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSelect(int index) {
|
||||||
|
if (index == 0) {
|
||||||
|
Updates.launchUpdate(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,9 @@
|
||||||
ui.quickslotbutton.select_item=Quickslot an item
|
ui.quickslotbutton.select_item=Quickslot an item
|
||||||
|
|
||||||
ui.toolbar.examine_prompt=Press again to search\nPress a tile to examine
|
ui.toolbar.examine_prompt=Press again to search\nPress a tile to examine
|
||||||
|
|
||||||
|
ui.updatenotification.title=Update
|
||||||
|
ui.updatenotification$wndupdate.title=An Update is Available!
|
||||||
|
ui.updatenotification$wndupdate.versioned_title=Update Available: %s
|
||||||
|
ui.updatenotification$wndupdate.desc=Shattered Pixel Dungeon is regularly updated with overhauls to existing game content, or entirely new content!\n\nGame balance is also frequently improved in game updates, so that specific items/heroes/enemies aren't too strong or too weak.\n\nUpdates also include fixes for bugs and other various stability improvements.
|
||||||
|
ui.updatenotification$wndupdate.button=Go To Update Page
|
|
@ -20,6 +20,10 @@ task debug(dependsOn: classes, type: JavaExec) {
|
||||||
systemProperty 'Specification-Title', appName
|
systemProperty 'Specification-Title', appName
|
||||||
systemProperty 'Specification-Version', appVersionName + "-INDEV"
|
systemProperty 'Specification-Version', appVersionName + "-INDEV"
|
||||||
systemProperty 'Implementation-Version', appVersionCode
|
systemProperty 'Implementation-Version', appVersionCode
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
debugImplementation project(':services:updates:debugUpdates')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//need a separate task to compile dependencies first, seeing as we're setting them up in an odd way
|
//need a separate task to compile dependencies first, seeing as we're setting them up in an odd way
|
||||||
|
@ -38,6 +42,10 @@ task release(dependsOn: compileForRelease, type: Jar) {
|
||||||
attributes 'Specification-Version': appVersionName
|
attributes 'Specification-Version': appVersionName
|
||||||
attributes 'Implementation-Version': appVersionCode
|
attributes 'Implementation-Version': appVersionCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
releaseImplementation project(':services:updates:githubUpdates')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -47,4 +55,8 @@ dependencies {
|
||||||
implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
|
implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
|
||||||
implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
|
implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
|
||||||
implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
|
implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
|
||||||
|
|
||||||
|
//Need these at compile time to prevent errors there.
|
||||||
|
// The actual dependency used at runtime will vary based on source set.
|
||||||
|
compileOnly project(':services:updates:debugUpdates')
|
||||||
}
|
}
|
|
@ -29,6 +29,8 @@ import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Preferences;
|
||||||
import com.badlogic.gdx.utils.SharedLibraryLoader;
|
import com.badlogic.gdx.utils.SharedLibraryLoader;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
|
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
|
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.services.updates.UpdateImpl;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates;
|
||||||
import com.watabou.noosa.Game;
|
import com.watabou.noosa.Game;
|
||||||
import com.watabou.utils.FileUtils;
|
import com.watabou.utils.FileUtils;
|
||||||
import com.watabou.utils.Point;
|
import com.watabou.utils.Point;
|
||||||
|
@ -79,6 +81,10 @@ public class DesktopLauncher {
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
Game.versionCode = Integer.parseInt(System.getProperty("Implementation-Version"));
|
Game.versionCode = Integer.parseInt(System.getProperty("Implementation-Version"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (UpdateImpl.supportsUpdates()){
|
||||||
|
Updates.service = UpdateImpl.getUpdateService();
|
||||||
|
}
|
||||||
|
|
||||||
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
|
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,11 @@ public class DesktopPlatformSupport extends PlatformSupport {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean connectedToUnmeteredNetwork() {
|
||||||
|
return true; //no easy way to check this in desktop, just assume user doesn't care
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void promptTextInput(String title, String hintText, int maxLen, boolean multiLine, String posTxt, String negTxt, TextCallback callback) {
|
public void promptTextInput(String title, String hintText, int maxLen, boolean multiLine, String posTxt, String negTxt, TextCallback callback) {
|
||||||
|
|
||||||
|
|
4
services/build.gradle
Normal file
4
services/build.gradle
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
apply plugin: 'java-library'
|
||||||
|
|
||||||
|
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||||
|
sourceCompatibility = targetCompatibility = appJavaCompatibility
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 Evan Debenham
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
|
||||||
|
|
||||||
|
public class AvailableUpdateData {
|
||||||
|
|
||||||
|
public String versionName;
|
||||||
|
public int versionCode;
|
||||||
|
|
||||||
|
public String desc;
|
||||||
|
|
||||||
|
public String URL;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 Evan Debenham
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
|
||||||
|
|
||||||
|
public abstract class UpdateService {
|
||||||
|
|
||||||
|
public static abstract class UpdateResultCallback {
|
||||||
|
public abstract void onUpdateAvailable( AvailableUpdateData update );
|
||||||
|
public abstract void onNoUpdateFound();
|
||||||
|
public abstract void onConnectionFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void checkForUpdate( UpdateResultCallback callback );
|
||||||
|
|
||||||
|
public abstract void initializeUpdate( AvailableUpdateData update );
|
||||||
|
|
||||||
|
}
|
9
services/updates/debugUpdates/build.gradle
Normal file
9
services/updates/debugUpdates/build.gradle
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
apply plugin: 'java-library'
|
||||||
|
|
||||||
|
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||||
|
sourceCompatibility = targetCompatibility = appJavaCompatibility
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':SPD-classes')
|
||||||
|
api project(':services')
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 Evan Debenham
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
|
||||||
|
|
||||||
|
|
||||||
|
import com.watabou.noosa.Game;
|
||||||
|
import com.watabou.utils.DeviceCompat;
|
||||||
|
|
||||||
|
public class DebugUpdates extends UpdateService {
|
||||||
|
|
||||||
|
private static AvailableUpdateData debugUpdateInfo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkForUpdate(UpdateResultCallback callback) {
|
||||||
|
|
||||||
|
//turn on to test update UI
|
||||||
|
if (false){
|
||||||
|
debugUpdateInfo = new AvailableUpdateData();
|
||||||
|
debugUpdateInfo.versionCode = Game.versionCode+1;
|
||||||
|
debugUpdateInfo.URL = "http://www.google.com";
|
||||||
|
|
||||||
|
callback.onUpdateAvailable(debugUpdateInfo);
|
||||||
|
} else {
|
||||||
|
debugUpdateInfo = null;
|
||||||
|
|
||||||
|
callback.onNoUpdateFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeUpdate(AvailableUpdateData update) {
|
||||||
|
DeviceCompat.openURI( update.URL );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 Evan Debenham
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
|
||||||
|
|
||||||
|
public class UpdateImpl {
|
||||||
|
|
||||||
|
private static UpdateService updateChecker = new DebugUpdates();
|
||||||
|
|
||||||
|
public static UpdateService getUpdateService(){
|
||||||
|
return updateChecker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean supportsUpdates(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
9
services/updates/githubUpdates/build.gradle
Normal file
9
services/updates/githubUpdates/build.gradle
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
apply plugin: 'java-library'
|
||||||
|
|
||||||
|
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||||
|
sourceCompatibility = targetCompatibility = appJavaCompatibility
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':SPD-classes')
|
||||||
|
api project(':services')
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 Evan Debenham
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
|
||||||
|
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.Net;
|
||||||
|
import com.watabou.noosa.Game;
|
||||||
|
import com.watabou.utils.Bundle;
|
||||||
|
import com.watabou.utils.DeviceCompat;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLProtocolException;
|
||||||
|
|
||||||
|
public class GitHubUpdates extends UpdateService {
|
||||||
|
|
||||||
|
private static Pattern descPattern = Pattern.compile("(.*?)(\r\n|\n|\r)(\r\n|\n|\r)---", Pattern.DOTALL + Pattern.MULTILINE);
|
||||||
|
private static Pattern versionCodePattern = Pattern.compile("internal version number: ([0-9]*)", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkForUpdate(UpdateResultCallback callback) {
|
||||||
|
|
||||||
|
if (!Game.platform.connectedToUnmeteredNetwork()){
|
||||||
|
callback.onConnectionFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
Net.HttpRequest httpGet = new Net.HttpRequest(Net.HttpMethods.GET);
|
||||||
|
httpGet.setUrl("https://api.github.com/repos/00-Evan/shattered-pixel-dungeon/releases");
|
||||||
|
httpGet.setHeader("Accept", "application/vnd.github.v3+json");
|
||||||
|
|
||||||
|
Gdx.net.sendHttpRequest(httpGet, new Net.HttpResponseListener() {
|
||||||
|
@Override
|
||||||
|
public void handleHttpResponse(Net.HttpResponse httpResponse) {
|
||||||
|
try {
|
||||||
|
Bundle latestRelease = null;
|
||||||
|
int latestVersionCode = Game.versionCode;
|
||||||
|
|
||||||
|
boolean includePrereleases = Game.version.toLowerCase().contains("beta");
|
||||||
|
|
||||||
|
for (Bundle b : Bundle.read( httpResponse.getResultAsStream() ).getBundleArray()){
|
||||||
|
Matcher m = versionCodePattern.matcher(b.getString("body"));
|
||||||
|
|
||||||
|
if (m.find()){
|
||||||
|
int releaseVersion = Integer.parseInt(m.group(1));
|
||||||
|
if (releaseVersion > latestVersionCode
|
||||||
|
&& (includePrereleases || !b.getBoolean("prerelease"))){
|
||||||
|
latestRelease = b;
|
||||||
|
latestVersionCode = releaseVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (latestRelease == null){
|
||||||
|
callback.onNoUpdateFound();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
AvailableUpdateData update = new AvailableUpdateData();
|
||||||
|
|
||||||
|
update.versionName = latestRelease.getString("name");
|
||||||
|
update.versionCode = latestVersionCode;
|
||||||
|
Matcher m = descPattern.matcher(latestRelease.getString("body"));
|
||||||
|
m.find();
|
||||||
|
update.desc = m.group(1);
|
||||||
|
update.URL = latestRelease.getString("html_url");
|
||||||
|
|
||||||
|
callback.onUpdateAvailable(update);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Game.reportException( e );
|
||||||
|
callback.onConnectionFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed(Throwable t) {
|
||||||
|
//Failure in SSL handshake, possibly because GitHub requires TLS 1.2+.
|
||||||
|
// Often happens for old OS versions with outdated security protocols.
|
||||||
|
// Future update attempts won't work anyway, so just pretend nothing was found.
|
||||||
|
if (t instanceof SSLProtocolException){
|
||||||
|
callback.onNoUpdateFound();
|
||||||
|
} else {
|
||||||
|
Game.reportException(t);
|
||||||
|
callback.onConnectionFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelled() {
|
||||||
|
callback.onConnectionFailed();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeUpdate(AvailableUpdateData update) {
|
||||||
|
DeviceCompat.openURI( update.URL );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 Evan Debenham
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.services.updates;
|
||||||
|
|
||||||
|
public class UpdateImpl {
|
||||||
|
|
||||||
|
private static UpdateService updateChecker = new GitHubUpdates();
|
||||||
|
|
||||||
|
public static UpdateService getUpdateService(){
|
||||||
|
return updateChecker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean supportsUpdates(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1 +1,2 @@
|
||||||
include ':core', ':SPD-classes', ':android', ':desktop'
|
include ':core', ':SPD-classes', ':android', ':desktop', ':services',
|
||||||
|
':services:updates:debugUpdates', ':services:updates:githubUpdates'
|
Loading…
Reference in New Issue
Block a user