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

Re-enable analytics

This commit is contained in:
tobspr 2020-06-24 17:59:43 +02:00
parent 25cf1ea93b
commit b3de1f9207
9 changed files with 85 additions and 57 deletions

View File

@ -36,7 +36,6 @@ module.exports = ({ watch = false, standalone = false }) => {
lzString.compressToEncodedURIComponent("http://localhost:10005/v1") lzString.compressToEncodedURIComponent("http://localhost:10005/v1")
), ),
G_IS_DEV: "true", G_IS_DEV: "true",
G_IS_PROD: "false",
G_IS_RELEASE: "false", G_IS_RELEASE: "false",
G_IS_MOBILE_APP: "false", G_IS_MOBILE_APP: "false",
G_IS_BROWSER: "true", G_IS_BROWSER: "true",

View File

@ -24,7 +24,6 @@ module.exports = ({
assertAlways: "window.assert", assertAlways: "window.assert",
abstract: "window.assert(false, 'abstract method called');", abstract: "window.assert(false, 'abstract method called');",
G_IS_DEV: "false", G_IS_DEV: "false",
G_IS_PROD: "true",
G_IS_RELEASE: environment === "prod" ? "true" : "false", G_IS_RELEASE: environment === "prod" ? "true" : "false",
G_IS_STANDALONE: standalone ? "true" : "false", G_IS_STANDALONE: standalone ? "true" : "false",
G_IS_BROWSER: isBrowser ? "true" : "false", G_IS_BROWSER: isBrowser ? "true" : "false",

View File

@ -33,6 +33,7 @@ import { MainMenuState } from "./states/main_menu";
import { MobileWarningState } from "./states/mobile_warning"; import { MobileWarningState } from "./states/mobile_warning";
import { PreloadState } from "./states/preload"; import { PreloadState } from "./states/preload";
import { SettingsState } from "./states/settings"; import { SettingsState } from "./states/settings";
import { ShapezGameAnalytics } from "./platform/browser/game_analytics";
const logger = createLogger("application"); const logger = createLogger("application");
@ -130,8 +131,7 @@ export class Application {
this.adProvider = new NoAdProvider(this); this.adProvider = new NoAdProvider(this);
this.sound = new SoundImplBrowser(this); this.sound = new SoundImplBrowser(this);
this.analytics = new GoogleAnalyticsImpl(this); this.analytics = new GoogleAnalyticsImpl(this);
// this.gameAnalytics = new ShapezGameAnalytics(this); this.gameAnalytics = new ShapezGameAnalytics(this);
this.gameAnalytics = new NoGameAnalytics(this);
} }
/** /**

View File

@ -9,7 +9,7 @@ export const IS_DEBUG =
export const IS_DEMO = queryParamOptions.fullVersion export const IS_DEMO = queryParamOptions.fullVersion
? false ? false
: (G_IS_PROD && !G_IS_STANDALONE) || : (!G_IS_DEV && !G_IS_STANDALONE) ||
(typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0); (typeof window !== "undefined" && window.location.search.indexOf("demo") >= 0);
export const SUPPORT_TOUCH = false; export const SUPPORT_TOUCH = false;

View File

@ -769,7 +769,7 @@ export function quantizeFloat(value) {
* @param {number} tickRate Interval of the timer * @param {number} tickRate Interval of the timer
*/ */
export function checkTimerExpired(now, lastTick, tickRate) { export function checkTimerExpired(now, lastTick, tickRate) {
if (!G_IS_PROD) { if (G_IS_DEV) {
if (quantizeFloat(now) !== now) { if (quantizeFloat(now) !== now) {
console.error("Got non-quantizied time:" + now + " vs " + quantizeFloat(now)); console.error("Got non-quantizied time:" + now + " vs " + quantizeFloat(now));
now = quantizeFloat(now); now = quantizeFloat(now);

1
src/js/globals.d.ts vendored
View File

@ -1,7 +1,6 @@
// Globals defined by webpack // Globals defined by webpack
declare const G_IS_DEV: boolean; declare const G_IS_DEV: boolean;
declare const G_IS_PROD: boolean;
declare function assert(condition: boolean | object | string, ...errorMessage: string[]): void; declare function assert(condition: boolean | object | string, ...errorMessage: string[]): void;
declare function assertAlways(condition: boolean | object | string, ...errorMessage: string[]): void; declare function assertAlways(condition: boolean | object | string, ...errorMessage: string[]): void;

View File

@ -1,11 +1,12 @@
import { GameAnalyticsInterface } from "../game_analytics";
import { createLogger } from "../../core/logging";
import { ShapeDefinition } from "../../game/shape_definition";
import { Savegame } from "../../savegame/savegame";
import { FILE_NOT_FOUND } from "../storage";
import { globalConfig } from "../../core/config"; import { globalConfig } from "../../core/config";
import { InGameState } from "../../states/ingame"; import { createLogger } from "../../core/logging";
import { GameRoot } from "../../game/root"; import { GameRoot } from "../../game/root";
import { InGameState } from "../../states/ingame";
import { GameAnalyticsInterface } from "../game_analytics";
import { FILE_NOT_FOUND } from "../storage";
import { blueprintShape, UPGRADES } from "../../game/upgrades";
import { tutorialGoals } from "../../game/tutorial_goals";
import { BeltComponent } from "../../game/components/belt";
import { StaticMapEntityComponent } from "../../game/components/static_map_entity"; import { StaticMapEntityComponent } from "../../game/components/static_map_entity";
const logger = createLogger("game_analytics"); const logger = createLogger("game_analytics");
@ -14,16 +15,32 @@ const analyticsUrl = G_IS_DEV ? "http://localhost:8001" : "https://analytics.sha
// Be sure to increment the ID whenever it changes to make sure all // Be sure to increment the ID whenever it changes to make sure all
// users are tracked // users are tracked
const analyticsLocalFile = "analytics_token.3.bin"; const analyticsLocalFile = "shapez_token_123.bin";
export class ShapezGameAnalytics extends GameAnalyticsInterface { export class ShapezGameAnalytics extends GameAnalyticsInterface {
get environment() {
if (G_IS_DEV) {
return "dev";
}
if (G_IS_STANDALONE) {
return "steam";
}
if (G_IS_RELEASE) {
return "prod";
}
return "beta";
}
/** /**
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
initialize() { initialize() {
this.syncKey = null; this.syncKey = null;
setInterval(() => this.sendTimePoints(), 120 * 1000); setInterval(() => this.sendTimePoints(), 60 * 1000);
// Retrieve sync key from player // Retrieve sync key from player
return this.app.storage.readFileAsync(analyticsLocalFile).then( return this.app.storage.readFileAsync(analyticsLocalFile).then(
@ -38,7 +55,7 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
// Perform call to get a new key from the API // Perform call to get a new key from the API
this.sendToApi("/v1/register", { this.sendToApi("/v1/register", {
environment: G_APP_ENVIRONMENT, environment: this.environment,
}) })
.then(res => { .then(res => {
// Try to read and parse the key from the api // Try to read and parse the key from the api
@ -135,10 +152,12 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
playerKey: this.syncKey, playerKey: this.syncKey,
gameKey: savegameId, gameKey: savegameId,
ingameTime: root.time.now(), ingameTime: root.time.now(),
environment: this.environment,
category, category,
value, value,
version: G_BUILD_VERSION, version: G_BUILD_VERSION,
gameDump: this.generateGameDump(root, category === "sync"), level: root.hubGoals.level,
gameDump: this.generateGameDump(root),
}); });
} }
@ -151,52 +170,58 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
} }
/** /**
* Generates a game dump * Returns true if the shape is interesting
* @param {GameRoot} root * @param {string} key
* @param {boolean=} metaOnly
*/ */
generateGameDump(root, metaOnly = false) { isInterestingShape(key) {
let staticEntities = []; if (key === blueprintShape) {
return true;
}
const entities = root.entityMgr.getAllWithComponent(StaticMapEntityComponent); // Check if its a story goal
for (let i = 0; i < tutorialGoals.length; ++i) {
// Limit the entities if (key === tutorialGoals[i].shape) {
if (!metaOnly && entities.length < 500) { return true;
for (let i = 0; i < entities.length; ++i) {
const entity = entities[i];
const staticComp = entity.components.StaticMapEntity;
const payload = {};
payload.origin = staticComp.origin;
payload.tileSize = staticComp.tileSize;
payload.rotation = staticComp.rotation;
if (entity.components.Belt) {
payload.type = "belt";
} else if (entity.components.UndergroundBelt) {
payload.type = "tunnel";
} else if (entity.components.ItemProcessor) {
payload.type = entity.components.ItemProcessor.type;
} else if (entity.components.Miner) {
payload.type = "extractor";
} else {
logger.warn("Unkown entity type", entity);
}
staticEntities.push(payload);
} }
} }
return { // Check if its required to unlock an upgrade
storedShapes: root.hubGoals.storedShapes, for (const upgradeKey in UPGRADES) {
gainedRewards: root.hubGoals.gainedRewards, const handle = UPGRADES[upgradeKey];
upgradeLevels: root.hubGoals.upgradeLevels, const tiers = handle.tiers;
staticEntities, for (let i = 0; i < tiers.length; ++i) {
}; const tier = tiers[i];
const required = tier.required;
for (let k = 0; k < required.length; ++k) {
if (required[k].shape === key) {
return true;
}
}
}
}
return false;
} }
/** /**
* @param {ShapeDefinition} definition * Generates a game dump
* @param {GameRoot} root
*/ */
handleShapeDelivered(definition) {} generateGameDump(root) {
const shapeIds = Object.keys(root.hubGoals.storedShapes).filter(this.isInterestingShape.bind(this));
let shapes = {};
for (let i = 0; i < shapeIds.length; ++i) {
shapes[shapeIds[i]] = root.hubGoals.storedShapes[shapeIds[i]];
}
return {
shapes,
upgrades: root.hubGoals.upgradeLevels,
belts: root.entityMgr.getAllWithComponent(BeltComponent).length,
buildings:
root.entityMgr.getAllWithComponent(StaticMapEntityComponent).length -
root.entityMgr.getAllWithComponent(BeltComponent).length,
};
}
/** /**
*/ */
@ -204,6 +229,12 @@ export class ShapezGameAnalytics extends GameAnalyticsInterface {
this.sendGameEvent("game_start", ""); this.sendGameEvent("game_start", "");
} }
/**
*/
handleGameResumed() {
this.sendTimePoints();
}
/** /**
* Handles the given level completed * Handles the given level completed
* @param {number} level * @param {number} level

View File

@ -25,9 +25,9 @@ export class GameAnalyticsInterface {
handleGameStarted() {} handleGameStarted() {}
/** /**
* @param {ShapeDefinition} definition * Handles a resumed game
*/ */
handleShapeDelivered(definition) {} handleGameResumed() {}
/** /**
* Handles the given level completed * Handles the given level completed

View File

@ -217,7 +217,6 @@ export class InGameState extends GameState {
this.core.initializeRoot(this, this.savegame); this.core.initializeRoot(this, this.savegame);
if (this.savegame.hasGameDump()) { if (this.savegame.hasGameDump()) {
this.app.gameAnalytics.handleGameStarted();
this.stage4bResumeGame(); this.stage4bResumeGame();
} else { } else {
this.app.gameAnalytics.handleGameStarted(); this.app.gameAnalytics.handleGameStarted();
@ -245,6 +244,7 @@ export class InGameState extends GameState {
this.onInitializationFailure("Savegame is corrupt and can not be restored."); this.onInitializationFailure("Savegame is corrupt and can not be restored.");
return; return;
} }
this.app.gameAnalytics.handleGameResumed();
this.stage5FirstUpdate(); this.stage5FirstUpdate();
} }
} }