Skip to content

Commit

Permalink
[release] 0.1.111
Browse files Browse the repository at this point in the history
  • Loading branch information
insraq committed Jan 16, 2024
1 parent 32fe8d2 commit 3577b53
Show file tree
Hide file tree
Showing 54 changed files with 502 additions and 356 deletions.
1 change: 1 addition & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"recommended": true,
"a11y": { "all": false },
"performance": { "noDelete": "warn" },
"suspicious": {"noExplicitAny":"warn"},
"style": {
"useSelfClosingElements": "off",
"noNonNullAssertion": "warn",
Expand Down
4 changes: 2 additions & 2 deletions src/scripts/Bootstrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export async function startGame(
}
const petraOfflineTime = actualOfflineTime - offlineTime;
if (petra) {
const storage = getStorageFor(petra.xy, gameState);
const storage = getStorageFor(petra.tile, gameState);
if (!petra.building.resources.Warp) {
petra.building.resources.Warp = 0;
}
Expand Down Expand Up @@ -199,7 +199,7 @@ function showOfflineProductionProgress(progress: number, routeTo: RouteTo): Prom

function findSpecialBuildings(gameState: GameState): ISpecialBuildings {
const buildings: Partial<Record<Building, ITileData>> = {};
forEach(gameState.tiles, (_, tile) => {
gameState.tiles.forEach((tile) => {
if (tile.building?.type === "Headquarter") {
console.assert(
buildings.Headquarter === undefined,
Expand Down
45 changes: 38 additions & 7 deletions src/scripts/Global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import type { GameOptions } from "./logic/GameState";
import { GameState, SavedGame, initializeGameState } from "./logic/GameState";
import { rollPermanentGreatPeople } from "./logic/RebornLogic";
import { getGreatPeopleChoices } from "./logic/TechLogic";
import { makeBuilding } from "./logic/Tile";
import { makeBuilding, type ITileData } from "./logic/Tile";
import { SteamClient, isSteam } from "./rpc/SteamClient";
import { Grid } from "./scenes/Grid";
import { WorldScene } from "./scenes/WorldScene";
import { idbGet, idbSet } from "./utilities/BrowserStorage";
import { firstKeyOf, forEach } from "./utilities/Helper";
import { firstKeyOf, forEach, xyToTile, type Tile } from "./utilities/Helper";
import { makeObservableHook } from "./utilities/Hook";
import { Singleton } from "./utilities/Singleton";
import { TypedEvent } from "./utilities/TypedEvent";
Expand Down Expand Up @@ -47,7 +47,7 @@ if (import.meta.env.DEV) {
window.clearGame = wipeSaveData;
// @ts-expect-error
window.clearAllResources = () => {
forEach(getGameState().tiles, (xy, tile) => {
getGameState().tiles.forEach((tile) => {
if (tile.building) {
tile.building.resources = {};
}
Expand Down Expand Up @@ -127,12 +127,30 @@ export async function compressSave(gs: SavedGame = savedGame): Promise<Uint8Arra
return await compress(serializeSave(gs));
}

function replacer(key: string, value: any): any {
if (value instanceof Map) {
return {
$type: "Map",
value: Array.from(value.entries()), // or with spread: value: [...value]
};
}
return value;
}
function reviver(key: string, value: any): any {
if (typeof value === "object" && value !== null) {
if (value.$type === "Map") {
return new Map(value.value);
}
}
return value;
}

export function serializeSave(gs: SavedGame = savedGame): Uint8Array {
return new TextEncoder().encode(JSON.stringify(gs));
return new TextEncoder().encode(JSON.stringify(gs, replacer));
}

export function deserializeSave(bytes: Uint8Array): SavedGame {
return JSON.parse(new TextDecoder().decode(bytes));
return JSON.parse(new TextDecoder().decode(bytes), reviver);
}

export async function decompressSave(data: Uint8Array): Promise<SavedGame> {
Expand Down Expand Up @@ -204,8 +222,21 @@ export function watchGameOptions(cb: (gameOptions: GameOptions) => void): () =>
export const useGameState = makeObservableHook(GameStateChanged, getGameState);
export const useGameOptions = makeObservableHook(GameOptionsChanged, getGameOptions);

function migrateSavedGame(gs: SavedGame) {
forEach(gs.current.tiles, (xy, tile) => {
function migrateSavedGame(save: SavedGame) {
if (!(save.current.tiles instanceof Map)) {
const tiles = new Map<Tile, ITileData>();
forEach(save.current.tiles as Record<string, ITileData>, (xy, tile) => {
if ("xy" in tile) {
// @ts-expect-error
tile.tile = xyToTile(tile.xy);
delete tile.xy;
}
tiles.set(xyToTile(xy), tile);
});
save.current.tiles = tiles;
save.current.transportation = new Map();
}
save.current.tiles.forEach((tile) => {
if (tile.building) {
if (!Config.Building[tile.building.type]) {
delete tile.building;
Expand Down
3 changes: 2 additions & 1 deletion src/scripts/Route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getGameState } from "./Global";
import { clearShortcuts } from "./logic/Shortcut";
import { LoadingPage } from "./ui/LoadingPage";
import { TilePage } from "./ui/TilePage";
import type { Tile } from "./utilities/Helper";
import type { TypedEvent } from "./utilities/TypedEvent";
import { playClick } from "./visuals/Sound";

Expand All @@ -15,7 +16,7 @@ export function Route({ event }: { event: TypedEvent<RouteChangeEvent> }) {
function handleRouteChanged(e: RouteChangeEvent) {
if (import.meta.env.DEV) {
if (e.component === TilePage) {
console.log(getGameState().tiles[e.params.xy as string]);
console.log(getGameState().tiles.get(e.params.xy as Tile));
}
}
if (e.component !== LoadingPage) {
Expand Down
10 changes: 10 additions & 0 deletions src/scripts/definitions/PatchNotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ interface PatchNote {
}

export const PatchNotes: PatchNote[] = [
{
version: "0.1.111",
content: [
[
"QoL",
"This patch contains a significant performance improvement. The save data will be automatically migrated but you might want to take a backup first",
],
["Bugfix", "Fix Not Producing Buildings on the resource panel does not work"],
],
},
{
version: "0.1.110",
content: [
Expand Down
72 changes: 37 additions & 35 deletions src/scripts/logic/BuildingLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import {
isEmpty,
isNullOrUndefined,
keysOf,
mReduceOf,
mapSafeAdd,
mapSafePush,
reduceOf,
safeAdd,
safePush,
sizeOf,
sum,
xyToPoint,
tileToPoint,
type Tile,
} from "../utilities/Helper";
import { srand } from "../utilities/Random";
import type { Textures } from "../utilities/SceneManager";
Expand Down Expand Up @@ -59,7 +61,7 @@ export function getTileTexture(r: Resource, textures: Textures) {
return textures[`Tile${r}`];
}

export function totalMultiplierFor(xy: string, type: keyof Multiplier, base: number, gs: GameState): number {
export function totalMultiplierFor(xy: Tile, type: keyof Multiplier, base: number, gs: GameState): number {
let result = base;
forEachMultiplier(
xy,
Expand All @@ -72,12 +74,12 @@ export function totalMultiplierFor(xy: string, type: keyof Multiplier, base: num
}

function forEachMultiplier(
xy: string,
xy: Tile,
func: (m: MultiplierWithSource) => void,
gs: GameState,
): MultiplierWithSource[] {
const result: MultiplierWithSource[] = [];
const b = gs.tiles[xy].building;
const b = gs.tiles.get(xy)?.building;
Tick.current.tileMultipliers.get(xy)?.forEach((m) => func(m));
if (b) {
Tick.current.buildingMultipliers.get(b.type)?.forEach((m) => func(m));
Expand All @@ -86,7 +88,7 @@ function forEachMultiplier(
return result;
}

export function getMultipliersFor(xy: string, gs: GameState): MultiplierWithSource[] {
export function getMultipliersFor(xy: Tile, gs: GameState): MultiplierWithSource[] {
const result: MultiplierWithSource[] = [];
forEachMultiplier(xy, (m) => result.push(m), gs);
return result;
Expand Down Expand Up @@ -156,7 +158,7 @@ interface IWorkerRequirement {
}

export function getWorkersFor(
xy: string,
xy: Tile,
filter: { include: Partial<Record<Resource, number>> } | { exclude: Partial<Record<Resource, number>> },
gs: GameState,
): IWorkerRequirement {
Expand All @@ -165,7 +167,7 @@ export function getWorkersFor(
multiplier: 1,
output: 0,
};
const b = gs.tiles[xy].building;
const b = gs.tiles.get(xy)?.building;
if (b) {
forEach(getBuildingIO(xy, "output", IOCalculation.Capacity, gs), (k, v) => {
if ("include" in filter && k in filter.include) {
Expand All @@ -183,7 +185,7 @@ export function getWorkersFor(
}

export function checkBuildingMax(k: Building, gs: GameState): boolean {
const buildingCount = reduceOf(
const buildingCount = mReduceOf(
gs.tiles,
(prev, _xy, tile) => prev + (tile.building?.type === k ? 1 : 0),
0,
Expand All @@ -205,11 +207,11 @@ interface IStorageResult {
// 1 hour
const STORAGE_TO_PRODUCTION = 3600;

export function getStorageFor(xy: string, gs: GameState): IStorageResult {
export function getStorageFor(xy: Tile, gs: GameState): IStorageResult {
const accumulate = (prev: number, k: Resource, v: number): number => {
return isTransportable(k) ? prev + v : prev;
};
const building = gs.tiles[xy].building;
const building = gs.tiles.get(xy)?.building;
const used = reduceOf(building?.resources, accumulate, 0);
let multiplier = totalMultiplierFor(xy, "storage", 1, gs);

Expand Down Expand Up @@ -237,7 +239,7 @@ export function getStorageFor(xy: string, gs: GameState): IStorageResult {
case "StPetersBasilica": {
let count = 0;
getBuildingsThatProduce("Faith").forEach((b) => {
forEach(getBuildingsByType(b, gs), (xy, tile) => {
getBuildingsByType(b, gs)?.forEach((tile, xy) => {
if (tile.building.status === "completed") {
count += tile.building.level;
}
Expand Down Expand Up @@ -280,14 +282,14 @@ export function addWorkers(res: Resource, amount: number): void {
safeAdd(Tick.next.workersAvailable, res, amount);
}

export function useWorkers(res: Resource, amount: number, xy: string | null): void {
export function useWorkers(res: Resource, amount: number, xy: Tile | null): void {
if (Config.Resource[res].canStore) {
console.error("`useWorkers` can only be called with non-transportable resource!");
return;
}
// Normally, we write to Tick.next and read from Tick.current. This is the only exception!
safeAdd(Tick.current.workersUsed, res, amount);
if (!xy) {
if (isNullOrUndefined(xy)) {
return;
}
switch (res) {
Expand All @@ -312,8 +314,8 @@ export function getResourceName(r: Resource): string {
return Config.Resource[r].name();
}

export function getBuildingName(xy: string, gs: GameState): string {
const type = gs.tiles[xy].building?.type;
export function getBuildingName(xy: Tile, gs: GameState): string {
const type = gs.tiles.get(xy)?.building?.type;
if (!type) {
return "";
}
Expand Down Expand Up @@ -343,16 +345,16 @@ export function addTransportation(
amount: number,
fuelResource: Resource,
fuelAmount: number,
fromXy: string,
toXy: string,
fromXy: Tile,
toXy: Tile,
gs: GameState,
): void {
const fromGrid = xyToPoint(fromXy);
const fromGrid = tileToPoint(fromXy);
const fromPosition = Singleton().grid.gridToPosition(fromGrid);
const toGrid = xyToPoint(toXy);
const toGrid = tileToPoint(toXy);
const toPosition = Singleton().grid.gridToPosition(toGrid);
useWorkers(fuelResource, fuelAmount, null);
safePush(gs.transportation, toXy, {
mapSafePush(gs.transportation, toXy, {
id: ++gs.transportId,
fromXy,
toXy,
Expand Down Expand Up @@ -490,8 +492,7 @@ export function getCurrentPriority(building: IBuildingData): number {

export function getTotalBuildingUpgrades(gs: GameState): number {
let result = 0;

forEach(getXyBuildings(gs), (xy, building) => {
getXyBuildings(gs).forEach((building) => {
if (!isSpecialBuilding(building.type)) {
result += building.level;
}
Expand All @@ -505,8 +506,8 @@ interface BuildingPercentageResult {
cost: PartialTabulate<Resource>;
}

export function getBuildingPercentage(xy: string, gs: GameState): BuildingPercentageResult {
const building = gs.tiles[xy]?.building;
export function getBuildingPercentage(xy: Tile, gs: GameState): BuildingPercentageResult {
const building = gs.tiles.get(xy)?.building;
if (!building) {
return { percent: 0, secondsLeft: Infinity, cost: {} };
}
Expand Down Expand Up @@ -589,7 +590,7 @@ export function getWarehouseIdleCapacity(warehouse: IWarehouseBuildingData): num

export function getBuilderCapacity(
building: IHaveTypeAndLevel,
xy: string,
xy: Tile,
gs: GameState,
): { multiplier: number; base: number; total: number } {
const builder =
Expand Down Expand Up @@ -619,19 +620,19 @@ export function applyToAllBuildings<T extends IBuildingData>(
getOptions: (b: IBuildingData) => Partial<T>,
gs: GameState,
) {
forEach(getBuildingsByType(building, gs), (xy, tile) => {
getBuildingsByType(building, gs)?.forEach((tile, xy) => {
Object.assign(tile.building, getOptions(tile.building));
});
}

export function getMarketPrice(resource: Resource, xy: string, gs: GameState): number {
export function getMarketPrice(resource: Resource, xy: Tile, gs: GameState): number {
const rand = srand(gs.lastPriceUpdated + xy + resource);
const fluctuation = 0.75 + rand() * 0.5;
return (Config.ResourcePrice[resource] ?? 0) * fluctuation;
}

export function getAvailableResource(xy: string, res: Resource, gs: GameState): number {
const building = getXyBuildings(gs)[xy];
export function getAvailableResource(xy: Tile, res: Resource, gs: GameState): number {
const building = getXyBuildings(gs).get(xy);

if (!building) {
return 0;
Expand Down Expand Up @@ -664,9 +665,10 @@ export function getAvailableResource(xy: string, res: Resource, gs: GameState):
return building.resources[res]!;
}

export function exploreTile(xy: string, gs: GameState): void {
if (!gs.tiles[xy].explored) {
gs.tiles[xy].explored = true;
export function exploreTile(xy: Tile, gs: GameState): void {
const tile = gs.tiles.get(xy);
if (tile && !tile.explored) {
tile.explored = true;
onTileExplored(xy, gs);
}
}
Expand Down Expand Up @@ -703,8 +705,8 @@ export const ElectrificationStatus = {

export type ElectrificationStatus = keyof typeof ElectrificationStatus;

export function getElectrificationStatus(xy: string, gs: GameState): ElectrificationStatus {
const building = gs.tiles[xy].building;
export function getElectrificationStatus(xy: Tile, gs: GameState): ElectrificationStatus {
const building = gs.tiles.get(xy)?.building;
if (!building || !canBeElectrified(building.type)) {
return "NotActive";
}
Expand Down
Loading

0 comments on commit 3577b53

Please sign in to comment.