Merge branch 'funkin-mobile/main' of github.com:FunkinCrew/Funkin-secret into funkin-mobile/main
This commit is contained in:
+1
-1
Submodule art updated: 78dc310219...e5eafbad4a
@@ -227,7 +227,7 @@
|
||||
"name": "extension-iapcore",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "46a8b945fb6fbfbf3cff313e8110f62413ad286f",
|
||||
"ref": "cb0195ff33903a28f483d2092a7420854ecdfdf5",
|
||||
"url": "https://github.com/MAJigsaw77/extension-iapcore"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -493,11 +493,13 @@ class FunkinHitbox extends FlxTypedSpriteGroup<FunkinHint>
|
||||
hint.centerOrigin();
|
||||
hint.centerOffsets();
|
||||
});
|
||||
|
||||
hint.onUp.add(() -> {
|
||||
hint.animation.play('static', true);
|
||||
hint.centerOrigin();
|
||||
hint.centerOffsets();
|
||||
});
|
||||
|
||||
hint.onOut.add(() -> {
|
||||
hint.animation.play('static', true);
|
||||
hint.centerOrigin();
|
||||
@@ -526,7 +528,7 @@ class FunkinHitbox extends FlxTypedSpriteGroup<FunkinHint>
|
||||
{
|
||||
final matrix:Matrix = new Matrix();
|
||||
matrix.createGradientBox(width, height, 0, 0, 0);
|
||||
shape.graphics.beginGradientFill(RADIAL, [baseColor.to24Bit(), baseColor.to24Bit()], [0, 1], [60, 255], matrix, PAD, RGB, 0);
|
||||
shape.graphics.beginGradientFill(RADIAL, [baseColor.to24Bit(), baseColor.to24Bit()], [0, baseColor.alphaFloat], [60, 255], matrix, PAD, RGB, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -544,16 +546,19 @@ class FunkinHitbox extends FlxTypedSpriteGroup<FunkinHint>
|
||||
function createHintLaneLabelGraphic(width:Int, height:Int, labelHeight:Int, baseColor:FlxColor = 0xFFFFFFFF):FlxGraphic
|
||||
{
|
||||
final shape:Shape = new Shape();
|
||||
|
||||
shape.graphics.beginFill(0, 0);
|
||||
shape.graphics.drawRect(0, 0, width, height);
|
||||
shape.graphics.endFill();
|
||||
|
||||
shape.graphics.beginFill(baseColor.to24Bit(), baseColor.alphaFloat);
|
||||
final matrix:Matrix = new Matrix();
|
||||
matrix.createGradientBox(width, labelHeight, Math.PI / 2, 0, 0);
|
||||
shape.graphics.beginGradientFill(LINEAR, [baseColor.to24Bit(), baseColor.to24Bit()], [baseColor.alphaFloat, 0], [0, 255], matrix);
|
||||
shape.graphics.drawRect(0, 0, width, labelHeight);
|
||||
shape.graphics.endFill();
|
||||
|
||||
shape.graphics.beginFill(baseColor.to24Bit(), baseColor.alphaFloat);
|
||||
final matrix:Matrix = new Matrix();
|
||||
matrix.createGradientBox(width, labelHeight, Math.PI / 2, 0, height - labelHeight);
|
||||
shape.graphics.beginGradientFill(LINEAR, [baseColor.to24Bit(), baseColor.to24Bit()], [0, baseColor.alphaFloat], [0, 255], matrix);
|
||||
shape.graphics.drawRect(0, height - labelHeight, width, labelHeight);
|
||||
shape.graphics.endFill();
|
||||
|
||||
@@ -578,7 +583,7 @@ class FunkinHitbox extends FlxTypedSpriteGroup<FunkinHint>
|
||||
{
|
||||
final matrix:Matrix = new Matrix();
|
||||
matrix.createGradientBox(width, height, 0, 0, 0);
|
||||
shape.graphics.beginGradientFill(RADIAL, [baseColor.to24Bit(), baseColor.to24Bit()], [0, 1], [60, 255], matrix, PAD, RGB, 0);
|
||||
shape.graphics.beginGradientFill(RADIAL, [baseColor.to24Bit(), baseColor.to24Bit()], [0, baseColor.alphaFloat], [60, 255], matrix, PAD, RGB, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,13 +4,12 @@ package funkin.mobile.util;
|
||||
import extension.iapcore.android.IAPAndroid;
|
||||
import extension.iapcore.android.IAPProductDetails;
|
||||
import extension.iapcore.android.IAPPurchase;
|
||||
import extension.iapcore.android.IAPPurchaseState;
|
||||
import extension.iapcore.android.IAPResponseCode;
|
||||
import extension.iapcore.android.IAPResult;
|
||||
|
||||
/**
|
||||
* Utility class for managing in-app purchases in a mobile application.
|
||||
* This class provides functions to initialize the in-app purchase system,
|
||||
* handle purchase events, and manage the purchase flow for different types
|
||||
* of in-app products, including consumables and non-consumables.
|
||||
* Utility class for managing in-app purchases.
|
||||
*/
|
||||
class InAppPurchasesUtil
|
||||
{
|
||||
@@ -19,10 +18,25 @@ class InAppPurchasesUtil
|
||||
*/
|
||||
static final FETCH_PRODUCT_DETAILS_IDS:Array<String> = ['test_product_0'];
|
||||
|
||||
/**
|
||||
* The maximum number of attempts to reconnect in case of a failure.
|
||||
*/
|
||||
static final MAX_RECONNECT_ATTEMPTS:Int = 3;
|
||||
|
||||
/**
|
||||
* A static variable that holds an array of currently loaded product details for in-app purchases.
|
||||
*/
|
||||
public static var currentLoadedProductDetails:Array<IAPProductDetails> = [];
|
||||
public static var currentProductDetails:Array<IAPProductDetails> = [];
|
||||
|
||||
/**
|
||||
* A static variable that holds an array of currently purchased for in-app purchases.
|
||||
*/
|
||||
public static var currentPurchased:Array<IAPPurchase> = [];
|
||||
|
||||
/**
|
||||
* A static variable to track the number of attempts made to reconnect.
|
||||
*/
|
||||
static var reconnectAttempts:Int = 0;
|
||||
|
||||
/**
|
||||
* Initializes the in-app purchases utility.
|
||||
@@ -33,42 +47,67 @@ class InAppPurchasesUtil
|
||||
logMessage(message);
|
||||
});
|
||||
|
||||
IAPAndroid.onBillingSetupFinished.add(function(code:IAPResponseCode, message:String):Void {
|
||||
if (message != null && message.length > 0) logMessage('IAP Setup finished with code "$code" "$message"!');
|
||||
else
|
||||
IAPAndroid.onBillingSetupFinished.add(function(result:IAPResult):Void {
|
||||
if (result.getResponseCode() != IAPResponseCode.OK)
|
||||
{
|
||||
logMessage('IAP Setup finished with code "$code"!');
|
||||
logMessage('Billing setup failed "$result"!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == IAPResponseCode.OK)
|
||||
{
|
||||
IAPAndroid.queryPurchases();
|
||||
reconnectAttempts = 0;
|
||||
|
||||
IAPAndroid.queryProductDetails(FETCH_PRODUCT_DETAILS_IDS);
|
||||
}
|
||||
IAPAndroid.queryPurchases();
|
||||
|
||||
IAPAndroid.queryProductDetails(FETCH_PRODUCT_DETAILS_IDS);
|
||||
});
|
||||
|
||||
IAPAndroid.onBillingServiceDisconnected.add(function():Void {
|
||||
logMessage("IAP Billing service disconnected!");
|
||||
});
|
||||
logMessage("Billing service disconnected!");
|
||||
|
||||
IAPAndroid.onProductDetailsResponse.add(function(code:IAPResponseCode, productDetails:Array<IAPProductDetails>):Void {
|
||||
logMessage('IAP Product details responded with code "$code", $productDetails');
|
||||
|
||||
currentLoadedProductDetails = productDetails;
|
||||
|
||||
for (productDetails in currentLoadedProductDetails)
|
||||
if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS)
|
||||
{
|
||||
logMessage('IAP Product details with title: ${productDetails.getTitle()}');
|
||||
reconnectAttempts++;
|
||||
|
||||
logMessage('Attempting to reconnect... ($reconnectAttempts/$MAX_RECONNECT_ATTEMPTS)');
|
||||
|
||||
IAPAndroid.startConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
logMessage('Max reconnect attempts reached.');
|
||||
}
|
||||
});
|
||||
|
||||
IAPAndroid.onQueryPurchasesResponse.add(function(code:IAPResponseCode, purchases:Array<IAPPurchase>):Void {
|
||||
logMessage('IAP Query purchases responded with code "$code", $purchases');
|
||||
IAPAndroid.onProductDetailsResponse.add(function(result:IAPResult, productDetails:Array<IAPProductDetails>):Void {
|
||||
if (result.getResponseCode() == IAPResponseCode.OK) currentProductDetails = productDetails;
|
||||
else
|
||||
{
|
||||
logMessage('Failed to fetch product details: "$result"');
|
||||
}
|
||||
});
|
||||
|
||||
IAPAndroid.onPurchasesUpdated.add(function(code:IAPResponseCode, purchases:Array<IAPPurchase>):Void {
|
||||
logMessage('IAP Purchases updated response with code "$code", $purchases');
|
||||
IAPAndroid.onQueryPurchasesResponse.add(function(result:IAPResult, purchases:Array<IAPPurchase>):Void {
|
||||
if (result.getResponseCode() == IAPResponseCode.OK) handlePurchases(purchases);
|
||||
else
|
||||
{
|
||||
logMessage('Failed to query purchases: "$result"');
|
||||
}
|
||||
});
|
||||
|
||||
IAPAndroid.onPurchasesUpdated.add(function(result:IAPResult, purchases:Array<IAPPurchase>):Void {
|
||||
if (result.getResponseCode() == IAPResponseCode.OK) handlePurchases(purchases);
|
||||
else
|
||||
{
|
||||
logMessage('Failed to update purchases: "$result"');
|
||||
}
|
||||
});
|
||||
|
||||
IAPAndroid.onAcknowledgePurchaseResponse.add(function(result:IAPResult):Void {
|
||||
if (result.getResponseCode() == IAPResponseCode.OK) logMessage('Purchase acknowledged successfully!');
|
||||
else
|
||||
{
|
||||
logMessage('Failed to acknowledge purchase: $result');
|
||||
}
|
||||
});
|
||||
|
||||
IAPAndroid.init();
|
||||
@@ -83,23 +122,36 @@ class InAppPurchasesUtil
|
||||
*/
|
||||
public static function purchase(id:String):Void
|
||||
{
|
||||
for (product in currentLoadedProductDetails)
|
||||
for (product in currentProductDetails)
|
||||
{
|
||||
if (product.getProductId() == id)
|
||||
{
|
||||
logMessage('Lunching purchase flow for ${product.getTitle()}');
|
||||
|
||||
IAPAndroid.launchPurchaseFlow(product);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
logMessage('Current ${product.getProductId()} doesnt match ${id}');
|
||||
}
|
||||
}
|
||||
|
||||
logMessage("Didn\'t Found Product Details for ID: " + id);
|
||||
logMessage("Didn't find product details for ID: " + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified product ID is already purchased.
|
||||
*
|
||||
* @param id The product ID to check.
|
||||
*
|
||||
* @return `true` if the product is already purchased and acknowledged, false otherwise.
|
||||
*/
|
||||
public static function isPurchased(id:String):Bool
|
||||
{
|
||||
for (purchase in currentPurchased)
|
||||
{
|
||||
if (purchase.getProducts().contains(id))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@:noCompletion
|
||||
@@ -109,7 +161,42 @@ class InAppPurchasesUtil
|
||||
android.widget.Toast.makeText(message, android.widget.Toast.LENGTH_SHORT);
|
||||
#end
|
||||
|
||||
trace(message);
|
||||
Sys.println(message);
|
||||
}
|
||||
|
||||
@:noCompletion
|
||||
private static function handlePurchases(purchases:Array<IAPPurchase>):Void
|
||||
{
|
||||
for (purchase in purchases)
|
||||
{
|
||||
if (purchase.getPurchaseState() == IAPPurchaseState.PURCHASED)
|
||||
{
|
||||
if (!purchase.isAcknowledged())
|
||||
{
|
||||
IAPAndroid.acknowledgePurchase(purchase.getPurchaseToken());
|
||||
}
|
||||
|
||||
var alreadyTracked:Bool = false;
|
||||
|
||||
for (existing in currentPurchased)
|
||||
{
|
||||
if (existing.getPurchaseToken() == purchase.getPurchaseToken())
|
||||
{
|
||||
alreadyTracked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadyTracked)
|
||||
{
|
||||
currentPurchased.push(purchase);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logMessage('Purchase not completed: ${purchase.getPurchaseState()}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
@@ -61,8 +61,15 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
|
||||
var xDiff:Float = value[0] - globalOffsets[0];
|
||||
var yDiff:Float = value[1] - globalOffsets[1];
|
||||
|
||||
this.x += xDiff * FullScreenScaleMode.windowScale.x;
|
||||
this.y += yDiff * FullScreenScaleMode.windowScale.y;
|
||||
this.x += xDiff;
|
||||
this.y += yDiff;
|
||||
|
||||
if (FullScreenScaleMode.windowScale.x != 1)
|
||||
{
|
||||
this.x *= fullscreenScale;
|
||||
this.y = this.y * fullscreenScale + (-100 * fullscreenScale);
|
||||
}
|
||||
|
||||
return globalOffsets = value;
|
||||
}
|
||||
|
||||
@@ -90,6 +97,16 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
|
||||
return this.speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* A value used for scaling object's parameters on mobile.
|
||||
*/
|
||||
var fullscreenScale(get, never):Float;
|
||||
|
||||
function get_fullscreenScale():Float
|
||||
{
|
||||
return FullScreenScaleMode.windowScale.x - 0.05;
|
||||
}
|
||||
|
||||
public function new(id:String)
|
||||
{
|
||||
super();
|
||||
@@ -190,8 +207,14 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
|
||||
public function setScale(scale:Null<Float>):Void
|
||||
{
|
||||
if (scale == null) scale = 1.0;
|
||||
this.boxSprite.scale.x = scale * FullScreenScaleMode.windowScale.x;
|
||||
this.boxSprite.scale.y = scale * FullScreenScaleMode.windowScale.y;
|
||||
|
||||
if (FullScreenScaleMode.windowScale.x != 1)
|
||||
{
|
||||
scale *= fullscreenScale;
|
||||
}
|
||||
|
||||
this.boxSprite.scale.x = scale;
|
||||
this.boxSprite.scale.y = scale;
|
||||
this.boxSprite.updateHitbox();
|
||||
}
|
||||
|
||||
@@ -275,7 +298,7 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
|
||||
function loadText():Void
|
||||
{
|
||||
textDisplay = new FlxTypeText(0, 0, 300, '', 32);
|
||||
textDisplay.fieldWidth = _data.text.width * FullScreenScaleMode.windowScale.x;
|
||||
textDisplay.fieldWidth = _data.text.width;
|
||||
textDisplay.setFormat(_data.text.fontFamily, _data.text.size, FlxColor.fromString(_data.text.color), LEFT, SHADOW,
|
||||
FlxColor.fromString(_data.text.shadowColor ?? '#00000000'), false);
|
||||
textDisplay.borderSize = _data.text.shadowWidth ?? 2;
|
||||
@@ -284,8 +307,15 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
|
||||
|
||||
textDisplay.completeCallback = onTypingComplete;
|
||||
|
||||
textDisplay.x += _data.text.offsets[0] * FullScreenScaleMode.windowScale.x;
|
||||
textDisplay.y += _data.text.offsets[1] * FullScreenScaleMode.windowScale.y;
|
||||
textDisplay.x += _data.text.offsets[0];
|
||||
textDisplay.y += _data.text.offsets[1];
|
||||
|
||||
if (FullScreenScaleMode.windowScale.x != 1)
|
||||
{
|
||||
textDisplay.fieldWidth *= fullscreenScale;
|
||||
textDisplay.x *= fullscreenScale;
|
||||
textDisplay.y *= fullscreenScale;
|
||||
}
|
||||
|
||||
add(textDisplay);
|
||||
}
|
||||
|
||||
@@ -64,11 +64,28 @@ class Speaker extends FlxSprite implements IDialogueScriptedClass implements IRe
|
||||
var xDiff:Float = value[0] - globalOffsets[0];
|
||||
var yDiff:Float = value[1] - globalOffsets[1];
|
||||
|
||||
this.x += xDiff * FullScreenScaleMode.windowScale.x;
|
||||
this.y += yDiff * FullScreenScaleMode.windowScale.y;
|
||||
this.x += xDiff;
|
||||
this.y += yDiff;
|
||||
|
||||
if (FullScreenScaleMode.windowScale.x != 1)
|
||||
{
|
||||
this.x *= fullscreenScale;
|
||||
this.y = this.y * fullscreenScale + (-100 * fullscreenScale);
|
||||
}
|
||||
|
||||
return globalOffsets = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A value used for scaling object's parameters on mobile.
|
||||
*/
|
||||
var fullscreenScale(get, never):Float;
|
||||
|
||||
function get_fullscreenScale():Float
|
||||
{
|
||||
return FullScreenScaleMode.windowScale.x - 0.05;
|
||||
}
|
||||
|
||||
public function new(id:String)
|
||||
{
|
||||
super();
|
||||
@@ -152,8 +169,14 @@ class Speaker extends FlxSprite implements IDialogueScriptedClass implements IRe
|
||||
public function setScale(scale:Null<Float>):Void
|
||||
{
|
||||
if (scale == null) scale = 1.0;
|
||||
this.scale.x = scale * FullScreenScaleMode.windowScale.y;
|
||||
this.scale.y = scale * FullScreenScaleMode.windowScale.y;
|
||||
|
||||
if (FullScreenScaleMode.windowScale.x != 1)
|
||||
{
|
||||
scale *= fullscreenScale;
|
||||
}
|
||||
|
||||
this.scale.x = scale;
|
||||
this.scale.y = scale;
|
||||
this.updateHitbox();
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ class CreditsState extends MusicBeatState
|
||||
// TODO: Once we need to display Kickstarter backers,
|
||||
// make this use a recycled pool so we don't kill peformance.
|
||||
creditsGroup = new FlxSpriteGroup();
|
||||
creditsGroup.x = SCREEN_PAD;
|
||||
creditsGroup.x = funkin.ui.FullScreenScaleMode.gameNotchSize.x + SCREEN_PAD;
|
||||
creditsGroup.y = STARTING_HEIGHT;
|
||||
|
||||
buildCreditsGroup();
|
||||
|
||||
@@ -176,18 +176,19 @@ class StoryMenuState extends MusicBeatState
|
||||
|
||||
updateProps();
|
||||
|
||||
tracklistText = new FlxText(FlxG.width * 0.05, levelBackground.x + levelBackground.height + 100, 0, "Tracks", 32);
|
||||
tracklistText = new FlxText(funkin.ui.FullScreenScaleMode.gameNotchSize.x + (FlxG.width * 0.05), levelBackground.x + levelBackground.height + 100, 0,
|
||||
"Tracks", 32);
|
||||
tracklistText.setFormat('VCR OSD Mono', 32);
|
||||
tracklistText.alignment = CENTER;
|
||||
tracklistText.color = 0xFFE55777;
|
||||
add(tracklistText);
|
||||
|
||||
scoreText = new FlxText(10, 10, 0, 'HIGH SCORE: 42069420');
|
||||
scoreText = new FlxText(funkin.ui.FullScreenScaleMode.gameNotchSize.x + 10, 10, 0, 'HIGH SCORE: 42069420');
|
||||
scoreText.setFormat('VCR OSD Mono', 32);
|
||||
scoreText.zIndex = 1000;
|
||||
add(scoreText);
|
||||
|
||||
levelTitleText = new FlxText(FlxG.width * 0.7, 10, 0, 'LEVEL 1');
|
||||
levelTitleText = new FlxText((FlxG.width * 0.7) - funkin.ui.FullScreenScaleMode.gameNotchSize.x, 10, 0, 'LEVEL 1');
|
||||
levelTitleText.setFormat('VCR OSD Mono', 32, FlxColor.WHITE, RIGHT);
|
||||
levelTitleText.alpha = 0.7;
|
||||
levelTitleText.zIndex = 1000;
|
||||
@@ -195,7 +196,7 @@ class StoryMenuState extends MusicBeatState
|
||||
|
||||
buildLevelTitles();
|
||||
|
||||
leftDifficultyArrow = new FlxSprite(FlxG.width - 410, 480);
|
||||
leftDifficultyArrow = new FlxSprite((FlxG.width - 410) - funkin.ui.FullScreenScaleMode.gameNotchSize.x, 480);
|
||||
leftDifficultyArrow.frames = Paths.getSparrowAtlas('storymenu/ui/arrows');
|
||||
leftDifficultyArrow.animation.addByPrefix('idle', 'leftIdle0');
|
||||
leftDifficultyArrow.animation.addByPrefix('press', 'leftConfirm0');
|
||||
@@ -205,7 +206,7 @@ class StoryMenuState extends MusicBeatState
|
||||
buildDifficultySprite(Constants.DEFAULT_DIFFICULTY);
|
||||
buildDifficultySprite();
|
||||
|
||||
rightDifficultyArrow = new FlxSprite(FlxG.width - 35, leftDifficultyArrow.y);
|
||||
rightDifficultyArrow = new FlxSprite((FlxG.width - 35) - funkin.ui.FullScreenScaleMode.gameNotchSize.x, leftDifficultyArrow.y);
|
||||
rightDifficultyArrow.frames = leftDifficultyArrow.frames;
|
||||
rightDifficultyArrow.animation.addByPrefix('idle', 'rightIdle0');
|
||||
rightDifficultyArrow.animation.addByPrefix('press', 'rightConfirm0');
|
||||
@@ -325,7 +326,8 @@ class StoryMenuState extends MusicBeatState
|
||||
scoreText.text = 'LEVEL SCORE: ${Math.round(highScoreLerp)}';
|
||||
|
||||
levelTitleText.text = currentLevel.getTitle();
|
||||
levelTitleText.x = FlxG.width - (levelTitleText.width + 10); // Right align.
|
||||
|
||||
levelTitleText.x = FlxG.width - (levelTitleText.width + 10) - funkin.ui.FullScreenScaleMode.gameNotchSize.x; // Right align.
|
||||
|
||||
handleKeyPresses();
|
||||
|
||||
@@ -680,6 +682,7 @@ class StoryMenuState extends MusicBeatState
|
||||
|
||||
tracklistText.screenCenter(X);
|
||||
tracklistText.x -= FlxG.width * 0.35;
|
||||
tracklistText.x += funkin.ui.FullScreenScaleMode.gameNotchSize.x;
|
||||
|
||||
var levelScore:Null<SaveScoreData> = Save.instance.getLevelScore(currentLevelId, currentDifficultyId);
|
||||
highScore = levelScore?.score ?? 0;
|
||||
|
||||
Reference in New Issue
Block a user