mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
Add achievements and accommodations for switching states
- Fix startup code to avoid clobbering achievements on state switch - Add a few more achievements
This commit is contained in:
parent
835317477d
commit
f5bfd9cf07
@ -3,6 +3,7 @@ import { GameRoot } from "./root";
|
|||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
import { createLogger } from "../core/logging";
|
import { createLogger } from "../core/logging";
|
||||||
|
import { ACHIEVEMENTS } from "../platform/achievement_provider";
|
||||||
|
|
||||||
const logger = createLogger("achievement_proxy");
|
const logger = createLogger("achievement_proxy");
|
||||||
|
|
||||||
@ -20,9 +21,10 @@ export class AchievementProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
this.provider.initialize(this.root)
|
this.provider.onLoad(this.root)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.log("Listening for unlocked achievements");
|
logger.log("Listening for unlocked achievements");
|
||||||
|
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.darkMode);
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
logger.error("Ignoring achievement signals", err);
|
logger.error("Ignoring achievement signals", err);
|
||||||
|
|||||||
@ -180,8 +180,8 @@ export class GameRoot {
|
|||||||
// for freeing space before actually placing.
|
// for freeing space before actually placing.
|
||||||
freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
freeEntityAreaBeforeBuild: /** @type {TypedSignal<[Entity]>} */ (new Signal()),
|
||||||
|
|
||||||
// Called with the key of the unlocked achievement
|
// Called with an achievement key and necessary args to validate it can be unlocked.
|
||||||
achievementUnlocked: /** @type {TypedSignal<[string]>} */ (new Signal()),
|
achievementUnlocked: /** @type {TypedSignal<[string, ...*]>} */ (new Signal()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// RNG's
|
// RNG's
|
||||||
|
|||||||
@ -254,6 +254,7 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
|
|||||||
|
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.theLogo, definition);
|
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.theLogo, definition);
|
||||||
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.toTheMoon, definition);
|
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.toTheMoon, definition);
|
||||||
|
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.fourLayers, definition);
|
||||||
|
|
||||||
// logger.log("Registered shape with key (2)", id);
|
// logger.log("Registered shape with key (2)", id);
|
||||||
return definition;
|
return definition;
|
||||||
|
|||||||
@ -7,30 +7,34 @@ import { ShapeDefinition } from "../game/shape_definition";
|
|||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
export const ACHIEVEMENTS = {
|
export const ACHIEVEMENTS = {
|
||||||
painting: "painting",
|
blueprints: "blueprints",
|
||||||
cutting: "cutting",
|
cutting: "cutting",
|
||||||
|
darkMode: "darkMode",
|
||||||
|
fourLayers: "fourLayers",
|
||||||
|
freedom: "freedom",
|
||||||
|
hundredShapes: "hundredShapes",
|
||||||
|
longBelt: "longBelt",
|
||||||
|
millionBlueprintShapes: "millionBlueprintShapes",
|
||||||
|
networked: "networked",
|
||||||
|
painting: "painting",
|
||||||
rotating: "rotating",
|
rotating: "rotating",
|
||||||
stacking: "stacking",
|
stacking: "stacking",
|
||||||
blueprints: "blueprints",
|
|
||||||
wires: "wires",
|
|
||||||
storage: "storage",
|
storage: "storage",
|
||||||
freedom: "freedom",
|
|
||||||
networked: "networked",
|
|
||||||
theLogo: "theLogo",
|
theLogo: "theLogo",
|
||||||
toTheMoon: "toTheMoon",
|
toTheMoon: "toTheMoon",
|
||||||
millionBlueprintShapes: "millionBlueprintShapes",
|
wires: "wires",
|
||||||
|
|
||||||
hundredShapes: "hundredShapes",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const BLUEPRINT_SHAPE = "CbCbCbRb:CwCwCwCw";
|
||||||
|
const DARK_MODE = "dark";
|
||||||
|
const FREEDOM_LEVEL = 26;
|
||||||
|
const LOGO_SHAPE = "RuCw--Cw:----Ru--";
|
||||||
|
const LONG_BELT_COUNT = 200;
|
||||||
|
const NETWORKED_WIRE_COUNT = 100;
|
||||||
const ONE_HUNDRED = 100;
|
const ONE_HUNDRED = 100;
|
||||||
const ONE_MILLION = 1000000;
|
const ONE_MILLION = 1000000;
|
||||||
const BLUEPRINT_SHAPE = "CbCbCbRb:CwCwCwCw";
|
|
||||||
const LOGO_SHAPE = "RuCw--Cw:----Ru--";
|
|
||||||
const ROCKET_SHAPE = "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw";
|
const ROCKET_SHAPE = "CbCuCbCu:Sr------:--CrSrCr:CwCwCwCw";
|
||||||
const FREEDOM_LEVEL = 26;
|
|
||||||
const WIRES_LEVEL = 20;
|
const WIRES_LEVEL = 20;
|
||||||
const NETWORKED_WIRE_COUNT = 100;
|
|
||||||
|
|
||||||
export class AchievementProviderInterface {
|
export class AchievementProviderInterface {
|
||||||
/** @param {Application} app */
|
/** @param {Application} app */
|
||||||
@ -47,6 +51,26 @@ export class AchievementProviderInterface {
|
|||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opportunity to do additional initialization work with the GameRoot.
|
||||||
|
* @param {GameRoot} root
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
onLoad(root) {
|
||||||
|
abstract;
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call to activate an achievement with the provider
|
||||||
|
* @param {string} key - Maps to an Achievement
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
activate(key) {
|
||||||
|
abstract;
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if achievements are supported in the current build
|
* Checks if achievements are supported in the current build
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
@ -61,14 +85,17 @@ export class Achievement {
|
|||||||
/** @param {string} key - An ACHIEVEMENTS key */
|
/** @param {string} key - An ACHIEVEMENTS key */
|
||||||
constructor(key) {
|
constructor(key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.unlocked = false;
|
|
||||||
this.signal = null;
|
|
||||||
this.receiver = null;
|
|
||||||
this.activate = null;
|
this.activate = null;
|
||||||
this.activatePromise = null;
|
this.activatePromise = null;
|
||||||
|
this.receiver = null;
|
||||||
|
this.signal = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid () {
|
isValid() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
isRelevant() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,18 +110,62 @@ export class Achievement {
|
|||||||
|
|
||||||
export class AchievementCollection {
|
export class AchievementCollection {
|
||||||
/**
|
/**
|
||||||
* @param {string[]} keys - An array of ACHIEVEMENTS keys
|
* @param {function} activate - Resolves when provider activation is complete
|
||||||
* @param {function} [activate] - Resolves when provider activation is complete
|
|
||||||
*/
|
*/
|
||||||
constructor(keys, activate) {
|
constructor(activate) {
|
||||||
this.map = new Map();
|
this.map = new Map();
|
||||||
this.activate = activate;
|
this.activate = activate;
|
||||||
|
this.initialized = false;
|
||||||
|
|
||||||
assert(Object.keys(ACHIEVEMENTS).length === keys.length, "Mismatched achievements");
|
this.createAndSet(ACHIEVEMENTS.blueprints, {
|
||||||
|
isValid: this.isBlueprintsValid
|
||||||
for (var i = 0; i < keys.length; i++) {
|
});
|
||||||
assert(ACHIEVEMENTS[keys[i]], "Achievement does not exist: " + keys[i]);
|
this.createAndSet(ACHIEVEMENTS.cutting);
|
||||||
}
|
this.createAndSet(ACHIEVEMENTS.darkMode, {
|
||||||
|
isValid: this.isDarkModeValid
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.fourLayers, {
|
||||||
|
isValid: this.isFourLayersValid
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.freedom, {
|
||||||
|
isRelevant: this.isFreedomRelevant,
|
||||||
|
isValid: this.isFreedomValid,
|
||||||
|
signal: "storyGoalCompleted"
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.hundredShapes, {
|
||||||
|
isRelevant: this.isHundredShapesRelevant,
|
||||||
|
isValid: this.isHundredShapesValid,
|
||||||
|
signal: "shapeDelivered"
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.longBelt, {
|
||||||
|
isValid: this.isLongBeltValid,
|
||||||
|
signal: "entityAdded"
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.millionBlueprintShapes, {
|
||||||
|
isValid: this.isMillionBlueprintShapesValid,
|
||||||
|
signal: "shapeDelivered"
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.networked, {
|
||||||
|
isValid: this.isNetworkedValid,
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.painting);
|
||||||
|
this.createAndSet(ACHIEVEMENTS.rotating);
|
||||||
|
this.createAndSet(ACHIEVEMENTS.stacking);
|
||||||
|
this.createAndSet(ACHIEVEMENTS.storage, {
|
||||||
|
isValid: this.isStorageValid,
|
||||||
|
signal: "entityGotNewComponent"
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.theLogo, {
|
||||||
|
isValid: this.isTheLogoValid
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.toTheMoon, {
|
||||||
|
isValid: this.isToTheMoonValid
|
||||||
|
});
|
||||||
|
this.createAndSet(ACHIEVEMENTS.wires, {
|
||||||
|
isRelevant: this.isWiresRelevant,
|
||||||
|
isValid: this.isWiresValid,
|
||||||
|
signal: "storyGoalCompleted"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {GameRoot} root */
|
/** @param {GameRoot} root */
|
||||||
@ -102,58 +173,49 @@ export class AchievementCollection {
|
|||||||
this.root = root;
|
this.root = root;
|
||||||
this.root.signals.achievementUnlocked.add(this.unlock, this);
|
this.root.signals.achievementUnlocked.add(this.unlock, this);
|
||||||
|
|
||||||
this.createAndSet(ACHIEVEMENTS.painting)
|
for (let [key, achievement] of this.map.entries()) {
|
||||||
this.createAndSet(ACHIEVEMENTS.cutting)
|
if (!achievement.isRelevant()) {
|
||||||
this.createAndSet(ACHIEVEMENTS.rotating)
|
this.remove(key);
|
||||||
this.createAndSet(ACHIEVEMENTS.stacking)
|
continue;
|
||||||
this.createAndSet(ACHIEVEMENTS.blueprints, this.isBlueprintsValid);
|
}
|
||||||
|
|
||||||
if (this.isWiresRelevant()) {
|
if (achievement.signal) {
|
||||||
this.createAndSet(ACHIEVEMENTS.wires, this.isWiresValid, "storyGoalCompleted");
|
achievement.receiver = this.unlock.bind(this, key);
|
||||||
|
this.root.signals[achievement.signal].add(achievement.receiver);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createAndSet(ACHIEVEMENTS.storage, this.isStorageValid, "entityGotNewComponent");
|
if (!this.hasDefaultReceivers()) {
|
||||||
|
this.root.signals.achievementUnlocked.remove(this.unlock);
|
||||||
if (this.isFreedomRelevant()) { // ...is it?
|
|
||||||
this.createAndSet(ACHIEVEMENTS.freedom, this.isFreedomValid, "storyGoalCompleted");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createAndSet(ACHIEVEMENTS.networked, this.isNetworkedValid);
|
this.initialized = true;
|
||||||
this.createAndSet(ACHIEVEMENTS.theLogo, this.isTheLogoValid);
|
|
||||||
this.createAndSet(ACHIEVEMENTS.toTheMoon, this.isToTheMoonValid);
|
|
||||||
this.createAndSet(
|
|
||||||
ACHIEVEMENTS.millionBlueprintShapes,
|
|
||||||
this.isMillionBlueprintShapesValid,
|
|
||||||
"shapeDelivered"
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.isHundredShapesRelevant()) {
|
|
||||||
this.createAndSet(
|
|
||||||
ACHIEVEMENTS.hundredShapes,
|
|
||||||
this.isHundredShapesValid,
|
|
||||||
"shapeDelivered"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} key - Maps to an Achievement
|
* @param {string} key - Maps to an Achievement
|
||||||
* @param {function} [isValid] - Validates achievement when a signal message is received
|
* @param {object} [options]
|
||||||
* @param {string} [signal] - Signal name to listen to for unlock attempts
|
* @param {function} [options.isValid]
|
||||||
|
* @param {function} [options.isRelevant]
|
||||||
|
* @param {string} [options.signal]
|
||||||
*/
|
*/
|
||||||
createAndSet(key, isValid, signal) {
|
createAndSet(key, options) {
|
||||||
const achievement = new Achievement(key);
|
const achievement = new Achievement(key);
|
||||||
|
|
||||||
achievement.activate = this.activate;
|
achievement.activate = this.activate;
|
||||||
|
|
||||||
if (isValid) {
|
if (options) {
|
||||||
achievement.isValid = isValid.bind(this);
|
if (options.isValid) {
|
||||||
}
|
achievement.isValid = options.isValid.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (signal) {
|
if (options.isRelevant) {
|
||||||
achievement.signal = signal;
|
achievement.isRelevant = options.isRelevant.bind(this);
|
||||||
achievement.receiver = this.unlock.bind(this, key);
|
}
|
||||||
this.root.signals[achievement.signal].add(achievement.receiver);
|
|
||||||
|
if (options.signal) {
|
||||||
|
achievement.signal = options.signal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.map.set(key, achievement);
|
this.map.set(key, achievement);
|
||||||
@ -165,39 +227,42 @@ export class AchievementCollection {
|
|||||||
*/
|
*/
|
||||||
unlock(key) {
|
unlock(key) {
|
||||||
if (!this.map.has(key)) {
|
if (!this.map.has(key)) {
|
||||||
console.log("Achievement unlocked or irrelevant:", key);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const achievement = this.map.get(key);
|
const achievement = this.map.get(key);
|
||||||
|
|
||||||
if (!achievement.isValid(...arguments)) {
|
if (!achievement.isValid(...arguments)) {
|
||||||
console.log("Achievement is invalid:", key);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return achievement.unlock()
|
return achievement.unlock()
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
if (achievement.receiver) {
|
this.remove(key);
|
||||||
this.root.signals[achievement.signal].remove(achievement.receiver);
|
|
||||||
console.log("Achievement receiver removed:", key);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.map.delete(key);
|
|
||||||
|
|
||||||
if (!this.hasDefaultReceivers()) {
|
if (!this.hasDefaultReceivers()) {
|
||||||
this.root.signals.achievementUnlocked.remove(this.unlock);
|
this.root.signals.achievementUnlocked.remove(this.unlock);
|
||||||
console.log("removed achievementUnlocked receiver");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {string} key - Maps to an Achievement */
|
||||||
|
remove(key) {
|
||||||
|
const achievement = this.map.get(key);
|
||||||
|
|
||||||
|
if (achievement.receiver) {
|
||||||
|
this.root.signals[achievement.signal].remove(achievement.receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.map.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
hasDefaultReceivers() {
|
hasDefaultReceivers() {
|
||||||
if (!this.map.size) {
|
if (!this.map.size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(let achievement of this.map.values()) {
|
for (let achievement of this.map.values()) {
|
||||||
if (!achievement.signal) {
|
if (!achievement.signal) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -303,4 +368,32 @@ export class AchievementCollection {
|
|||||||
isHundredShapesValid(key) {
|
isHundredShapesValid(key) {
|
||||||
return Object.keys(this.root.hubGoals.storedShapes).length === ONE_HUNDRED;
|
return Object.keys(this.root.hubGoals.storedShapes).length === ONE_HUNDRED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} key
|
||||||
|
* @param {ShapeDefinition} definition
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isFourLayersValid(key, definition) {
|
||||||
|
return definition.layers.length === 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} key
|
||||||
|
* @param {Entity} entity
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isLongBeltValid(key, entity) {
|
||||||
|
return entity.components.Belt &&
|
||||||
|
entity.components.Belt.assignedPath.totalLength >= LONG_BELT_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} key
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isDarkModeValid(key) {
|
||||||
|
return this.root.app.settings.currentData.settings.theme === DARK_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,11 @@ export class NoAchievementProvider extends AchievementProviderInterface {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock() {
|
onLoad() {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
activate() {
|
||||||
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { GamedistributionAdProvider } from "../ad_providers/gamedistribution";
|
|||||||
import { NoAdProvider } from "../ad_providers/no_ad_provider";
|
import { NoAdProvider } from "../ad_providers/no_ad_provider";
|
||||||
import { SteamAchievementProvider } from "../electron/steam_achievement_provider";
|
import { SteamAchievementProvider } from "../electron/steam_achievement_provider";
|
||||||
import { PlatformWrapperInterface } from "../wrapper";
|
import { PlatformWrapperInterface } from "../wrapper";
|
||||||
|
import { NoAchievementProvider } from "./no_achievement_provider";
|
||||||
import { StorageImplBrowser } from "./storage";
|
import { StorageImplBrowser } from "./storage";
|
||||||
import { StorageImplBrowserIndexedDB } from "./storage_indexed_db";
|
import { StorageImplBrowserIndexedDB } from "./storage_indexed_db";
|
||||||
|
|
||||||
@ -70,13 +71,9 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
|
|||||||
|
|
||||||
logger.log("Embed provider:", this.embedProvider.id);
|
logger.log("Embed provider:", this.embedProvider.id);
|
||||||
|
|
||||||
if (G_IS_DEV && globalConfig.debug.testAchievements) {
|
|
||||||
logger.log("Testing achievements");
|
|
||||||
this.app.achievementProvider = new SteamAchievementProvider(this.app);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.detectStorageImplementation()
|
return this.detectStorageImplementation()
|
||||||
.then(() => this.initializeAdProvider())
|
.then(() => this.initializeAdProvider())
|
||||||
|
.then(() => this.initializeAchievementProvider())
|
||||||
.then(() => super.initialize());
|
.then(() => super.initialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,6 +199,21 @@ export class PlatformWrapperImplBrowser extends PlatformWrapperInterface {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initializeAchievementProvider() {
|
||||||
|
if (G_IS_DEV && globalConfig.debug.testAchievements) {
|
||||||
|
this.app.achievementProvider = new SteamAchievementProvider(this.app);
|
||||||
|
|
||||||
|
return this.app.achievementProvider.initialize()
|
||||||
|
.catch(err => {
|
||||||
|
logger.error("Failed to initialize achievement provider, disabling:", err);
|
||||||
|
|
||||||
|
this.app.achievementProvider = new NoAchievementProvider(this.app);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.app.achievementProvider.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
exitApp() {
|
exitApp() {
|
||||||
// Can not exit app
|
// Can not exit app
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* typehints:start */
|
/* typehints:start */
|
||||||
import { Application } from "../../application";
|
import { Application } from "../../application";
|
||||||
import { Achievement } from "../achievement_provider";
|
import { GameRoot } from "../../game/root";
|
||||||
/* typehints:end */
|
/* typehints:end */
|
||||||
|
|
||||||
import { createLogger } from "../../core/logging";
|
import { createLogger } from "../../core/logging";
|
||||||
@ -14,20 +14,22 @@ import {
|
|||||||
const logger = createLogger("achievements/steam");
|
const logger = createLogger("achievements/steam");
|
||||||
|
|
||||||
const ACHIEVEMENT_IDS = {
|
const ACHIEVEMENT_IDS = {
|
||||||
[ACHIEVEMENTS.painting]: "<id>",
|
[ACHIEVEMENTS.blueprints]: "<id>",
|
||||||
[ACHIEVEMENTS.cutting]: "achievement_01", // Test ID
|
[ACHIEVEMENTS.cutting]: "achievement_01", // Test ID
|
||||||
|
[ACHIEVEMENTS.darkMode]: "<id>",
|
||||||
|
[ACHIEVEMENTS.fourLayers]: "<id>",
|
||||||
|
[ACHIEVEMENTS.freedom]: "<id>",
|
||||||
|
[ACHIEVEMENTS.hundredShapes]: "<id>",
|
||||||
|
[ACHIEVEMENTS.longBelt]: "<id>",
|
||||||
|
[ACHIEVEMENTS.millionBlueprintShapes]: "<id>",
|
||||||
|
[ACHIEVEMENTS.networked]: "<id>",
|
||||||
|
[ACHIEVEMENTS.painting]: "<id>",
|
||||||
[ACHIEVEMENTS.rotating]: "<id>",
|
[ACHIEVEMENTS.rotating]: "<id>",
|
||||||
[ACHIEVEMENTS.stacking]: "<id>",
|
[ACHIEVEMENTS.stacking]: "<id>",
|
||||||
[ACHIEVEMENTS.blueprints]: "<id>",
|
|
||||||
[ACHIEVEMENTS.wires]: "<id>",
|
|
||||||
[ACHIEVEMENTS.storage]: "<id>",
|
[ACHIEVEMENTS.storage]: "<id>",
|
||||||
[ACHIEVEMENTS.freedom]: "<id>",
|
|
||||||
[ACHIEVEMENTS.networked]: "<id>",
|
|
||||||
[ACHIEVEMENTS.theLogo]: "<id>",
|
[ACHIEVEMENTS.theLogo]: "<id>",
|
||||||
[ACHIEVEMENTS.toTheMoon]: "<id>",
|
[ACHIEVEMENTS.toTheMoon]: "<id>",
|
||||||
[ACHIEVEMENTS.millionBlueprintShapes]: "<id>",
|
[ACHIEVEMENTS.wires]: "<id>",
|
||||||
|
|
||||||
[ACHIEVEMENTS.hundredShapes]: "<id>",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export class SteamAchievementProvider extends AchievementProviderInterface {
|
export class SteamAchievementProvider extends AchievementProviderInterface {
|
||||||
@ -36,10 +38,9 @@ export class SteamAchievementProvider extends AchievementProviderInterface {
|
|||||||
super(app);
|
super(app);
|
||||||
|
|
||||||
this.initialized = false;
|
this.initialized = false;
|
||||||
this.keys = Object.keys(ACHIEVEMENT_IDS);
|
this.collection = new AchievementCollection(this.activate.bind(this));
|
||||||
this.collection = new AchievementCollection(this.keys, this.activate.bind(this));
|
|
||||||
|
|
||||||
logger.log("Steam achievement collection created");
|
logger.log("Collection created with", this.collection.map.size, "achievements");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,9 +50,23 @@ export class SteamAchievementProvider extends AchievementProviderInterface {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize (root) {
|
/** @param {GameRoot} root */
|
||||||
this.collection.initialize(root);
|
onLoad(root) {
|
||||||
|
if (this.collection.initialized) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.collection.initialize(root);
|
||||||
|
logger.log(this.collection.map.size, "achievements are relevant and initialized");
|
||||||
|
return Promise.resolve();
|
||||||
|
} catch (err) {
|
||||||
|
logger.error("Failed to initialize the achievement collection");
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
if (!G_IS_STANDALONE) {
|
if (!G_IS_STANDALONE) {
|
||||||
logger.warn("Steam unavailable. Achievements won't sync.");
|
logger.warn("Steam unavailable. Achievements won't sync.");
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@ -68,11 +83,7 @@ export class SteamAchievementProvider extends AchievementProviderInterface {
|
|||||||
} else {
|
} else {
|
||||||
logger.log("Steam achievement provider initialized");
|
logger.log("Steam achievement provider initialized");
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.catch(err => {
|
|
||||||
logger.error("Steam achievement provider error", err);
|
|
||||||
throw err;
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,10 +101,10 @@ export class SteamAchievementProvider extends AchievementProviderInterface {
|
|||||||
|
|
||||||
return promise
|
return promise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.log("Achievement unlocked:", key);
|
logger.log("Achievement activated:", key);
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
logger.error("Failed to unlock achievement:", key, err);
|
logger.error("Failed to activate achievement:", key, err);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { NoAchievementProvider } from "../browser/no_achievement_provider";
|
||||||
import { PlatformWrapperImplBrowser } from "../browser/wrapper";
|
import { PlatformWrapperImplBrowser } from "../browser/wrapper";
|
||||||
import { getIPCRenderer } from "../../core/utils";
|
import { getIPCRenderer } from "../../core/utils";
|
||||||
import { createLogger } from "../../core/logging";
|
import { createLogger } from "../../core/logging";
|
||||||
@ -22,7 +23,8 @@ export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
|
|||||||
this.app.storage = new StorageImplElectron(this);
|
this.app.storage = new StorageImplElectron(this);
|
||||||
this.app.achievementProvider = new SteamAchievementProvider(this.app);
|
this.app.achievementProvider = new SteamAchievementProvider(this.app);
|
||||||
|
|
||||||
return PlatformWrapperInterface.prototype.initialize.call(this);
|
return this.initializeAchievementProvider()
|
||||||
|
.then(() => PlatformWrapperInterface.prototype.initialize.call(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
steamOverlayFixRedrawCanvas() {
|
steamOverlayFixRedrawCanvas() {
|
||||||
@ -55,6 +57,15 @@ export class PlatformWrapperImplElectron extends PlatformWrapperImplBrowser {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initializeAchievementProvider() {
|
||||||
|
return this.app.achievementProvider.initialize()
|
||||||
|
.catch(err => {
|
||||||
|
logger.error("Failed to initialize achievement provider, disabling:", err);
|
||||||
|
|
||||||
|
this.app.achievementProvider = new NoAchievementProvider(this.app);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getSupportsFullscreen() {
|
getSupportsFullscreen() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user