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

[WIP] Implement painting, cutting, rotating achievements (to log only)

This commit is contained in:
Greg Considine 2021-02-22 16:02:52 -05:00
parent 261c7a4070
commit 85999f3f8b
5 changed files with 122 additions and 83 deletions

View File

@ -8,49 +8,29 @@ import { createLogger } from "../core/logging";
const logger = createLogger("achievement_manager");
export class AchievementManager {
static getId() {
return "AchievementManager";
}
constructor(root) {
this.root = root;
this.achievements = null;
this.achievements = this.root.app.achievements;
if (!this.root.app.achievements.hasAchievements()) {
logger.debug("Bypassing achievement set up");
// Set adhoc checks to reference a noop, ignore signals.
return;
}
this.init();
this.load()
}
init () {
return this.root.app.achievements.load()
load () {
return this.achievements.load()
.then(() => {
this.achievements = this.root.app.achievements.getAchievements();
if (!this.achievements.hasAchievements()) {
logger.log("Achievements disabled");
return;
}
return this.setChecks();
logger.log("There are", this.achievements.count, "achievements");
})
.catch(err => {
logger.error("Achievements failed to load", err);
})
}
setChecks () {
logger.debug("loaded", this.achievements);
// set checks on achievements
//this.root.signals.itemProduced.add(this.onItemProduced, this);
}
/**
* @param {BaseItem} item
*/
onItemProduced(item) {
logger.debug(item);
}
// Have one check function per achievement
isPainted () {
return
unlock (key) {
this.achievements.unlock(key);
}
}

View File

@ -4,6 +4,7 @@ import { enumColors } from "./colors";
import { ShapeItem } from "./items/shape_item";
import { GameRoot } from "./root";
import { enumSubShape, ShapeDefinition } from "./shape_definition";
import { ACHIEVEMENTS } from "../platform/achievements";
const logger = createLogger("shape_definition_manager");
@ -96,6 +97,8 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
const rightSide = definition.cloneFilteredByQuadrants([2, 3]);
const leftSide = definition.cloneFilteredByQuadrants([0, 1]);
this.root.achievementMgr.unlock(ACHIEVEMENTS.cutting);
return /** @type {[ShapeDefinition, ShapeDefinition]} */ (this.operationCache[key] = [
this.registerOrReturnHandle(rightSide),
this.registerOrReturnHandle(leftSide),
@ -137,6 +140,8 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
const rotated = definition.cloneRotateCW();
this.root.achievementMgr.unlock(ACHIEVEMENTS.rotating);
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
rotated
));
@ -203,9 +208,14 @@ export class ShapeDefinitionManager extends BasicSerializableObject {
*/
shapeActionPaintWith(definition, color) {
const key = "paint/" + definition.getHash() + "/" + color;
logger.debug("shapePainted", definition, color);
if (this.operationCache[key]) {
logger.debug("shapePaintedCache", definition, color);
return /** @type {ShapeDefinition} */ (this.operationCache[key]);
}
this.root.achievementMgr.unlock(ACHIEVEMENTS.painting);
const colorized = definition.cloneAndPaintWith(color);
return /** @type {ShapeDefinition} */ (this.operationCache[key] = this.registerOrReturnHandle(
colorized

View File

@ -2,6 +2,14 @@
import { Application } from "../application";
/* typehints:end */
export const ACHIEVEMENTS = {
painting: "painting",
cutting: "cutting",
rotating: "rotating",
stacking: "stacking",
blueprints: "blueprints",
}
export class AchievementsInterface {
constructor(app) {
/** @type {Application} */
@ -9,7 +17,30 @@ export class AchievementsInterface {
}
/**
* Initializes the list of achievements
* Load achievements into an initial state, bypassing unlocked and/or
* irrelevant achievements where possible.
*
* @params key
* @returns {Promise<void>}
*/
load() {
abstract;
return Promise.reject();
}
/**
* Call to unlock an achievement
* @params [key] - A property within the ACHIEVEMENTS enum or empty if
* bypassing.
* @returns {(undefined|Promise)}
*/
unlock(key) {
abstract;
return Promise.reject();
}
/**
* Initializes the list of achievements.
* @returns {Promise<void>}
*/
initialize() {

View File

@ -1,76 +1,87 @@
import { AchievementsInterface } from "../achievements";
import { ACHIEVEMENTS, AchievementsInterface } from "../achievements";
import { globalConfig } from "../../core/config";
import { createLogger } from "../../core/logging";
import { newEmptyMap } from "../../core/utils";
//import { T } from "../../translations";
const logger = createLogger("achievements/default");
const logger = createLogger("achievements/steam");
// Include API id per key
export const ACHIEVEMENTS = {
painting: "painting"
const IDS = {
painting: "<id>",
cutting: "<id>",
rotating: "<id>",
stacking: "<id>",
blueprints: "<id>"
}
export class Achievements extends AchievementsInterface {
initialize() {
this.authTicket = null;
this.achievementNames = null;
this.achievements = null;
this.connected = false;
this.connectPromise = Promise.resolve();
this.map = new Map();
this.type = "Steam";
this.count = 0;
if (globalConfig.debug.testAchievements) {
return Promise.resolve();
logger.log("Initializing", this.type, "achievements");
for (let key in ACHIEVEMENTS) {
this.map[key] = new Map();
this.map[key].id = IDS[key];
this.map[key].key = key;
this.map[key].unlocked = false;
this.map[key].relevant = true;
this.count++;
}
// Check for resolve in AchievementManager via load() to not block game state
// transition
this.connectPromise = this.fetchAuthTicket()
.then(() => this.fetchAchievementNames());
this.logOnly = globalConfig.debug.testAchievements;
return Promise.resolve();
}
fetchAuthTicket () {
return Promise.resolve();
}
fetchAchievementNames () {
return Promise.resolve();
}
load () {
this.achievements = newEmptyMap();
// TODO: inspect safe file and update achievements
// Consider removing load since there's no async behavior anticipated
return Promise.resolve();
}
for (let key in ACHIEVEMENTS) {
this.achievements[key] = newEmptyMap();
this.achievements[key].unlocked = false;
this.achievements[key].invalid = false;
/**
* @param {string} key
*/
unlock (key) {
let achievement = this.map[key];
if (!achievement) {
logger.error("Achievement does not exist:", key);
return;
}
return this.connectPromise
if (!achievement.relevant) {
logger.debug("Achievement unlocked/irrelevant:", key);
return;
}
achievement.activate = achievement.activate || this.activate(achievement)
.then(() => {
// factor in game state, save data, then Steam data (if accessible) as
// source of truth.
achievement.unlocked = true;
achievement.relevant = false;
logger.log("Achievement unlocked:", key);
})
.catch(err => {
logger.error("Failed to unlock achievement", err);
})
.finally(() => {
achievement.activate = null;
})
}
/**
* @param {string} key
*/
fetchAchievement (key) {
return Promise.resolve();
}
activate (achievement) {
if (this.logOnly) {
return Promise.resolve();
}
/**
* @param {string} key
*/
unlockAchievement (key) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
//TODO: Implement greenworks activate
getAchievements() {
return this.achievements;
return resolve();
});
}
hasAchievements() {

View File

@ -5,7 +5,14 @@ export class NoAchievements extends AchievementsInterface {
return Promise.resolve();
}
load() {
return Promise.resolve();
}
hasAchievements() {
return false;
}
unlock() {
}
}