1
0
mirror of https://github.com/tobspr/shapez.io.git synced 2025-06-13 13:04:03 +00:00

Add play time achievements

This commit is contained in:
Greg Considine 2021-03-04 15:24:34 -05:00
parent f827e1ba2f
commit 311a620527
6 changed files with 82 additions and 9 deletions

View File

@ -40,6 +40,9 @@ export const globalConfig = {
assetsSharpness: 1.5, assetsSharpness: 1.5,
shapesSharpness: 1.4, shapesSharpness: 1.4,
// Achievements
achievementSliceDuration: 30, // Seconds
// Production analytics // Production analytics
statisticsGraphDpi: 2.5, statisticsGraphDpi: 2.5,
statisticsGraphSlices: 100, statisticsGraphSlices: 100,

View File

@ -2,6 +2,7 @@
import { GameRoot } from "./root"; import { GameRoot } from "./root";
/* typehints:end */ /* typehints:end */
import { globalConfig } from "../core/config";
import { createLogger } from "../core/logging"; import { createLogger } from "../core/logging";
import { ACHIEVEMENTS } from "../platform/achievement_provider"; import { ACHIEVEMENTS } from "../platform/achievement_provider";
@ -12,6 +13,8 @@ export class AchievementProxy {
constructor(root) { constructor(root) {
this.root = root; this.root = root;
this.provider = this.root.app.achievementProvider; this.provider = this.root.app.achievementProvider;
this.lastSlice = 0;
this.disabled = true;
if (!this.provider.hasAchievements()) { if (!this.provider.hasAchievements()) {
return; return;
@ -21,13 +24,39 @@ export class AchievementProxy {
} }
onLoad() { onLoad() {
if (this.provider.hasLoaded()) {
this.disabled = false;
return;
}
this.provider.onLoad(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); this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.darkMode);
this.startSlice();
this.disabled = false;
}) })
.catch(err => { .catch(err => {
this.disabled = true;
logger.error("Ignoring achievement signals", err); logger.error("Ignoring achievement signals", err);
}) })
} }
startSlice() {
this.lastSlice = this.root.time.now();
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.play1h, this.lastSlice);
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.play10h, this.lastSlice);
this.root.signals.achievementUnlocked.dispatch(ACHIEVEMENTS.play20h, this.lastSlice);
}
update() {
if (this.disabled) {
return;
}
if (this.root.time.now() - this.lastSlice > globalConfig.achievementSliceDuration) {
this.startSlice();
}
}
} }

View File

@ -151,6 +151,9 @@ export class GameCore {
// Update analytics // Update analytics
root.productionAnalytics.update(); root.productionAnalytics.update();
// Check achievements
root.achievementProxy.update();
} }
}); });
} }
@ -276,6 +279,9 @@ export class GameCore {
// Update analytics // Update analytics
root.productionAnalytics.update(); root.productionAnalytics.update();
// Check achievements
root.achievementProxy.update();
} }
// Update automatic save after everything finished // Update automatic save after everything finished

View File

@ -18,6 +18,9 @@ export const ACHIEVEMENTS = {
paintShape: "paintShape", paintShape: "paintShape",
place5000Wires: "place5000Wires", place5000Wires: "place5000Wires",
placeBlueprint: "placeBlueprint", placeBlueprint: "placeBlueprint",
play1h: "play1h",
play10h: "play10h",
play20h: "play20h",
produceLogo: "produceLogo", produceLogo: "produceLogo",
produceMsLogo: "produceMsLogo", produceMsLogo: "produceMsLogo",
produceRocket: "produceRocket", produceRocket: "produceRocket",
@ -30,6 +33,9 @@ export const ACHIEVEMENTS = {
}; };
const DARK_MODE = "dark"; const DARK_MODE = "dark";
const HOUR_1 = 3600; // Seconds
const HOUR_10 = HOUR_1 * 10;
const HOUR_20 = HOUR_1 * 20;
const SHAPE_BLUEPRINT = "CbCbCbRb:CwCwCwCw"; const SHAPE_BLUEPRINT = "CbCbCbRb:CwCwCwCw";
const SHAPE_LOGO = "RuCw--Cw:----Ru--"; const SHAPE_LOGO = "RuCw--Cw:----Ru--";
const SHAPE_MS_LOGO = "RgRyRbRr"; const SHAPE_MS_LOGO = "RgRyRbRr";
@ -60,6 +66,12 @@ export class AchievementProviderInterface {
return Promise.reject(); return Promise.reject();
} }
/** @returns {boolean} */
hasLoaded() {
abstract;
return false;
}
/** /**
* Call to activate an achievement with the provider * Call to activate an achievement with the provider
* @param {string} key - Maps to an Achievement * @param {string} key - Maps to an Achievement
@ -114,7 +126,6 @@ export class AchievementCollection {
constructor(activate) { constructor(activate) {
this.map = new Map(); this.map = new Map();
this.activate = activate; this.activate = activate;
this.initialized = false;
this.createAndSet(ACHIEVEMENTS.belt500Tiles, { this.createAndSet(ACHIEVEMENTS.belt500Tiles, {
isValid: this.isBelt500TilesValid, isValid: this.isBelt500TilesValid,
@ -142,6 +153,9 @@ export class AchievementCollection {
this.createAndSet(ACHIEVEMENTS.placeBlueprint, { this.createAndSet(ACHIEVEMENTS.placeBlueprint, {
isValid: this.isPlaceBlueprintValid, isValid: this.isPlaceBlueprintValid,
}); });
this.createAndSet(ACHIEVEMENTS.play1h, this.createTimeOptions(HOUR_1));
this.createAndSet(ACHIEVEMENTS.play10h, this.createTimeOptions(HOUR_10));
this.createAndSet(ACHIEVEMENTS.play20h, this.createTimeOptions(HOUR_20));
this.createAndSet(ACHIEVEMENTS.produceLogo, this.createShapeOptions(SHAPE_LOGO)); this.createAndSet(ACHIEVEMENTS.produceLogo, this.createShapeOptions(SHAPE_LOGO));
this.createAndSet(ACHIEVEMENTS.produceRocket, this.createShapeOptions(SHAPE_ROCKET)); this.createAndSet(ACHIEVEMENTS.produceRocket, this.createShapeOptions(SHAPE_ROCKET));
this.createAndSet(ACHIEVEMENTS.produceMsLogo, this.createShapeOptions(SHAPE_MS_LOGO)); this.createAndSet(ACHIEVEMENTS.produceMsLogo, this.createShapeOptions(SHAPE_MS_LOGO));
@ -182,8 +196,6 @@ export class AchievementCollection {
if (!this.hasDefaultReceivers()) { if (!this.hasDefaultReceivers()) {
this.root.signals.achievementUnlocked.remove(this.unlock); this.root.signals.achievementUnlocked.remove(this.unlock);
} }
this.initialized = true;
} }
/** /**
@ -290,6 +302,13 @@ export class AchievementCollection {
} }
} }
createTimeOptions (duration) {
return {
isRelevant: () => this.root.time.now() < duration,
isValid: () => this.root.time.now() >= duration,
}
}
/** /**
* @param {string} key * @param {string} key
* @param {Entity} entity * @param {Entity} entity

View File

@ -5,6 +5,10 @@ export class NoAchievementProvider extends AchievementProviderInterface {
return false; return false;
} }
hasLoaded() {
return false;
}
initialize() { initialize() {
return Promise.resolve(); return Promise.resolve();
} }

View File

@ -21,6 +21,9 @@ const ACHIEVEMENT_IDS = {
[ACHIEVEMENTS.paintShape]: "paint_shape", [ACHIEVEMENTS.paintShape]: "paint_shape",
[ACHIEVEMENTS.place5000Wires]: "place_5000_wires", [ACHIEVEMENTS.place5000Wires]: "place_5000_wires",
[ACHIEVEMENTS.placeBlueprint]: "place_blueprint", [ACHIEVEMENTS.placeBlueprint]: "place_blueprint",
[ACHIEVEMENTS.play1h]: "play_1h",
[ACHIEVEMENTS.play10h]: "play_10h",
[ACHIEVEMENTS.play20h]: "play_20h",
[ACHIEVEMENTS.produceLogo]: "produce_logo", [ACHIEVEMENTS.produceLogo]: "produce_logo",
[ACHIEVEMENTS.produceMsLogo]: "produce_ms_logo", [ACHIEVEMENTS.produceMsLogo]: "produce_ms_logo",
[ACHIEVEMENTS.produceRocket]: "produce_rocket", [ACHIEVEMENTS.produceRocket]: "produce_rocket",
@ -38,26 +41,34 @@ export class SteamAchievementProvider extends AchievementProviderInterface {
super(app); super(app);
this.initialized = false; this.initialized = false;
this.loaded = false;
this.collection = new AchievementCollection(this.activate.bind(this)); this.collection = new AchievementCollection(this.activate.bind(this));
logger.log("Collection created with", this.collection.map.size, "achievements"); logger.log("Collection created with", this.collection.map.size, "achievements");
} }
/** /** @returns {boolean} */
* @returns {boolean}
*/
hasAchievements() { hasAchievements() {
return true; return true;
} }
/** @param {GameRoot} root */ /** @returns {boolean} */
hasLoaded() {
return this.loaded;
}
/**
* @param {GameRoot} root
* @returns {Promise<void>}
*/
onLoad(root) { onLoad(root) {
if (this.collection.initialized) { if (this.loaded) {
return Promise.resolve(); return Promise.resolve();
} }
try { try {
this.collection.initialize(root); this.collection.initialize(root);
this.loaded = true;
logger.log(this.collection.map.size, "achievements are relevant and initialized"); logger.log(this.collection.map.size, "achievements are relevant and initialized");
return Promise.resolve(); return Promise.resolve();
} catch (err) { } catch (err) {
@ -66,6 +77,7 @@ export class SteamAchievementProvider extends AchievementProviderInterface {
} }
} }
/** @returns {Promise<void>} */
initialize() { 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.");
@ -87,7 +99,7 @@ export class SteamAchievementProvider extends AchievementProviderInterface {
} }
/** /**
* @param {string} key - An ACHIEVEMENTS key * @param {string} key
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
activate(key) { activate(key) {