diff --git a/src/components/features/Buyable.vue b/src/components/features/Buyable.vue
index 1615ddb..e25f289 100644
--- a/src/components/features/Buyable.vue
+++ b/src/components/features/Buyable.vue
@@ -2,7 +2,7 @@
 	<div v-if="buyable.unlocked" style="display: grid">
 		<button :style="style" @click="buyable.buy" @mousedown="start" @mouseleave="stop" @mouseup="stop" @touchstart="start"
 			:class="{ feature: true, [layer || tab.layer]: true, buyable: true, can: buyable.canBuy, locked: !buyable.canAfford, bought }"
-			@touchend="stop" @touchcancel="stop">
+			@touchend="stop" @touchcancel="stop" :disabled="!buyable.canBuy">
 			<div v-if="title">
 				<component :is="title" />
 			</div>
diff --git a/src/components/features/Clickable.vue b/src/components/features/Clickable.vue
index 315643f..cedb6f9 100644
--- a/src/components/features/Clickable.vue
+++ b/src/components/features/Clickable.vue
@@ -2,7 +2,7 @@
 	<div v-if="clickable.unlocked">
 		<button :class="{ feature: true, [layer || tab.layer]: true, can: clickable.canClick, locked: !clickable.canClick }" :style="style"
 			@click="clickable.click" @mousedown="start" @mouseleave="stop" @mouseup="stop" @touchstart="start"
-			@touchend="stop" @touchcancel="stop">
+			@touchend="stop" @touchcancel="stop" :disabled="!clickable.canClick">
 			<div v-if="titleDisplay">
 				<component :is="titleDisplay" />
 			</div>
diff --git a/src/components/features/Gridable.vue b/src/components/features/Gridable.vue
index 517d7b9..c0f7902 100644
--- a/src/components/features/Gridable.vue
+++ b/src/components/features/Gridable.vue
@@ -1,7 +1,7 @@
 <template>
-	<button v-if="gridable.unlocked" :class="{ feature: true, tile: true, can: gridable.canClick, locked: !gridable.canClick}"
-		:style="style" @click="gridable.click"  @mousedown="start" @mouseleave="stop" @mouseup="stop" @touchstart="start"
-		@touchend="stop" @touchcancel="stop">
+	<button v-if="gridable.unlocked" :class="{ feature: true, tile: true, can: canClick, locked: !canClick}"
+		:style="style" @click="gridable.click" @mousedown="start" @mouseleave="stop" @mouseup="stop" @touchstart="start"
+		@touchend="stop" @touchcancel="stop" :disabled="!canClick">
 		<div v-if="title"><component :is="title" /></div>
 		<component :is="display" style="white-space: pre-line;" />
 		<branch-node :branches="gridable.branches" :id="id" featureType="gridable" />
@@ -33,9 +33,12 @@ export default {
 		gridable() {
 			return layers[this.layer || this.tab.layer].grids[this.id][this.cell];
 		},
+		canClick() {
+			return this.gridable.canClick;
+		},
 		style() {
 			return [
-				this.gridable.canClick ? { 'background-color': layers[this.layer || this.tab.layer].color } : {},
+				this.canClick ? { 'background-color': layers[this.layer || this.tab.layer].color } : {},
 				layers[this.layer || this.tab.layer].componentStyles?.gridable,
 				this.gridable.style
 			];
diff --git a/src/components/features/Upgrade.vue b/src/components/features/Upgrade.vue
index 3cd1260..3d46488 100644
--- a/src/components/features/Upgrade.vue
+++ b/src/components/features/Upgrade.vue
@@ -7,7 +7,7 @@
 			can: upgrade.canAfford && !upgrade.bought,
 			locked: !upgrade.canAfford && !upgrade.bought,
 			bought: upgrade.bought
-		}">
+		}" :disabled="!upgrade.canAfford && !upgrade.bought">
 		<component v-if="fullDisplay" :is="fullDisplay" />
 		<default-upgrade-display v-else :id="id" />
 		<branch-node :branches="upgrade.branches" :id="id" featureType="upgrade" />
diff --git a/src/components/tree/BranchNode.vue b/src/components/tree/BranchNode.vue
index f7c4a48..0c4fe17 100644
--- a/src/components/tree/BranchNode.vue
+++ b/src/components/tree/BranchNode.vue
@@ -55,7 +55,7 @@ export default {
 			if (typeof branch === 'string') {
 				return branch.includes('@') ? branch : `${this.featureType}@${branch}`;
 			}
-			if (!branch.target.includes('@')) {
+			if (!branch.target?.includes('@')) {
 				return { ...branch, target: `${branch.featureType || this.featureType}@${branch.target}` };
 			}
 			return branch;
diff --git a/src/components/tree/TreeNode.vue b/src/components/tree/TreeNode.vue
index cd9be89..0ced67f 100644
--- a/src/components/tree/TreeNode.vue
+++ b/src/components/tree/TreeNode.vue
@@ -12,7 +12,7 @@
 			small
 		}">
 		<LayerProvider :index="tab.index" :layer="id">
-			<button v-if="layer.shown" @click="clickTab" :style="style">
+			<button v-if="layer.shown" @click="clickTab" :style="style" :disabled="!unlocked">
 				<component :is="display" />
 				<branch-node :branches="layer.branches" :id="id" featureType="tree-node" />
 			</button>
diff --git a/src/store/layers.js b/src/store/layers.js
index 22a83ef..3758181 100644
--- a/src/store/layers.js
+++ b/src/store/layers.js
@@ -1,16 +1,19 @@
 import Vue from 'vue';
 import clone from 'lodash.clonedeep';
 import { isFunction, isPlainObject } from '../util/common';
-import { createProxy, createGridProxy, player } from './proxies';
+import { createProxy, createGridProxy, player as playerProxy } from './proxies';
 import Decimal from '../util/bignum';
 import store from './index';
 import { noCache, getStartingBuyables, getStartingClickables, getStartingChallenges, defaultLayerProperties } from '../util/layers';
+import { applyPlayerData } from '../util/save';
 
 export const layers = {};
 export const hotkeys = [];
 window.layers = layers;
 
-export function addLayer(layer) {
+export function addLayer(layer, player = null) {
+	player = player || playerProxy;
+
 	// Check for required properties
 	if (!('id' in layer)) {
 		console.error(`Cannot add layer without a "id" property!`, layer);
@@ -27,6 +30,18 @@ export function addLayer(layer) {
 	// Clone object to prevent modifying the original
 	layer = clone(layer);
 
+	player[layer.id] = applyPlayerData({
+		upgrades: [],
+		achievements: [],
+		milestones: [],
+		infoboxes: {},
+		buyables: getStartingBuyables(layer),
+		clickables: getStartingClickables(layer),
+		challenges: getStartingChallenges(layer),
+		grids: {},
+		...layer.startData?.()
+	}, player[layer.id]);
+
 	// Set default property values
 	layer = Object.assign({}, defaultLayerProperties, layer);
 	layer.layer = layer.id;
@@ -53,9 +68,6 @@ export function addLayer(layer) {
 		}
 	}
 	if (layer.upgrades) {
-		if (player[layer.id].upgrades == undefined) {
-			player[layer.id].upgrades = [];
-		}
 		for (let id in layer.upgrades) {
 			if (isPlainObject(layer.upgrades[id])) {
 				layer.upgrades[id].bought = function() {
@@ -128,9 +140,6 @@ export function addLayer(layer) {
 		}
 	}
 	if (layer.achievements) {
-		if (player[layer.id].achievements == undefined) {
-			player[layer.id].achievements = [];
-		}
 		for (let id in layer.achievements) {
 			if (isPlainObject(layer.achievements[id])) {
 				layer.achievements[id].earned = function() {
@@ -140,9 +149,6 @@ export function addLayer(layer) {
 		}
 	}
 	if (layer.challenges) {
-		if (player[layer.id].challenges == undefined) {
-			player[layer.id].challenges = getStartingChallenges(layer);
-		}
 		for (let id in layer.challenges) {
 			if (isPlainObject(layer.challenges[id])) {
 				if (layer.challenges[id].onComplete != undefined) {
@@ -229,9 +235,6 @@ export function addLayer(layer) {
 		}
 	}
 	if (layer.buyables) {
-		if (player[layer.id].buyables == undefined) {
-			player[layer.id].buyables = getStartingBuyables(layer);
-		}
 		if (layer.buyables.reset == undefined) {
 			layer.buyables.reset = noCache(function() {
 				player[this.layer].buyables = getStartingBuyables(layer);
@@ -272,9 +275,6 @@ export function addLayer(layer) {
 		}
 	}
 	if (layer.clickables) {
-		if (player[layer.id].clickables == undefined) {
-			player[layer.id].clickables = getStartingClickables(layer);
-		}
 		for (let id in layer.clickables) {
 			if (isPlainObject(layer.clickables[id])) {
 				layer.clickables[id].state = function() {
@@ -287,9 +287,6 @@ export function addLayer(layer) {
 		}
 	}
 	if (layer.milestones) {
-		if (player[layer.id].milestones == undefined) {
-			player[layer.id].milestones = [];
-		}
 		for (let id in layer.milestones) {
 			if (isPlainObject(layer.milestones[id])) {
 				layer.milestones[id].shown = function() {
@@ -319,10 +316,10 @@ export function addLayer(layer) {
 		}
 	}
 	if (layer.grids) {
-		if (player[layer.id].grids == undefined) {
-			player[layer.id].grids = {};
-		}
 		for (let id in layer.grids) {
+			if (player[layer.id].grids[id] == undefined) {
+				player[layer.id].grids[id] = {};
+			}
 			if (isPlainObject(layer.grids[id])) {
 				if (player[layer.id].grids[id] == undefined) {
 					player[layer.id].grids[id] = {};
diff --git a/src/util/save.js b/src/util/save.js
index 97f29ea..6de7618 100644
--- a/src/util/save.js
+++ b/src/util/save.js
@@ -1,6 +1,5 @@
 import modInfo from '../data/modInfo';
 import { getStartingData, getInitialLayers, fixOldSave } from '../data/mod';
-import { getStartingBuyables, getStartingClickables, getStartingChallenges } from './layers';
 import { player } from '../store/proxies';
 import Decimal from './bignum';
 
@@ -11,7 +10,7 @@ export const IMPORTING_WRONG_ID = "WRONG_ID";
 export const IMPORTING_FORCE = "FORCE";
 
 export function getInitialStore(playerData = {}) {
-	playerData = applyPlayerData({
+	return applyPlayerData({
 		id: `${modInfo.id}-0`,
 		name: "Default Save",
 		tabs: modInfo.initialTabs.slice(),
@@ -40,22 +39,6 @@ export function getInitialStore(playerData = {}) {
 		saveToImport: "",
 		saveToExport: ""
 	}, playerData);
-
-	Object.assign(playerData, getInitialLayers(playerData).reduce((acc, layer) => {
-		acc[layer.id] = applyPlayerData({
-			upgrades: [],
-			achievements: [],
-			milestones: [],
-			infoboxes: {},
-			buyables: getStartingBuyables(layer),
-			clickables: getStartingClickables(layer),
-			challenges: getStartingChallenges(layer),
-			...layer.startData?.()
-		}, playerData[layer.id]);
-		return acc;
-	}, {}));
-
-	return playerData;
 }
 
 export function save() {
@@ -121,7 +104,7 @@ export async function loadSave(playerData) {
 	for (let layer in layers) {
 		removeLayer(layer);
 	}
-	getInitialLayers(playerData).forEach(addLayer);
+	getInitialLayers(playerData).forEach(layer => addLayer(layer, playerData));
 
 	playerData = getInitialStore(playerData);
 	if (playerData.offlineProd) {
@@ -136,24 +119,31 @@ export async function loadSave(playerData) {
 
 	Object.assign(player, playerData);
 	for (let prop in player) {
-		if (!(prop in playerData)) {
+		if (!(prop in playerData) && !(prop in layers)) {
 			delete player[prop];
 		}
 	}
 }
 
-function applyPlayerData(target, source) {
+export function applyPlayerData(target, source, destructive = false) {
 	for (let prop in source) {
 		if (target[prop] == null) {
 			target[prop] = source[prop];
 		} else if (target[prop] instanceof Decimal) {
 			target[prop] = new Decimal(source[prop]);
 		} else if (Array.isArray(target[prop]) || typeof target[prop] === 'object') {
-			target[prop] = applyPlayerData(target[prop], source[prop]);
+			target[prop] = applyPlayerData(target[prop], source[prop], destructive);
 		} else {
 			target[prop] = source[prop];
 		}
 	}
+	if (destructive) {
+		for (let prop in target) {
+			if (!(prop in source)) {
+				delete target[prop];
+			}
+		}
+	}
 	return target;
 }