Initial commit

This commit is contained in:
Aslan 2025-11-22 12:07:34 -05:00
commit 423a0ba959
60 changed files with 4399 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules
dist

34
README.md Normal file
View file

@ -0,0 +1,34 @@
## Usage
Those templates dependencies are maintained via [pnpm](https://pnpm.io) via `pnpm up -Lri`.
This is the reason you see a `pnpm-lock.yaml`. That being said, any package manager will work. This file can be safely be removed once you clone a template.
```bash
$ npm install # or pnpm install or yarn install
```
### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
## Available Scripts
In the project directory, you can run:
### `npm run dev` or `npm start`
Runs the app in the development mode.<br>
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br>
### `npm run build`
Builds the app for production to the `dist` folder.<br>
It correctly bundles Solid in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br>
Your app is ready to be deployed!
## Deployment
You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.)

15
index.html Normal file
View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>Solid App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/index.tsx" type="module"></script>
</body>
</html>

2726
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

25
package.json Normal file
View file

@ -0,0 +1,25 @@
{
"name": "vite-template-solid",
"version": "0.0.0",
"description": "",
"type": "module",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"license": "MIT",
"devDependencies": {
"@tailwindcss/vite": "^4.1.17",
"solid-devtools": "^0.34.3",
"tailwindcss": "^4.1.17",
"typescript": "^5.9.2",
"vite": "^7.1.4",
"vite-plugin-solid": "^2.11.8"
},
"dependencies": {
"daisyui": "^5.5.5",
"solid-js": "^1.9.9"
}
}

126
src/App.tsx Normal file
View file

@ -0,0 +1,126 @@
import { onMount, type Component } from "solid-js";
import { dispatch, state } from "./store/state";
import { AllInventories } from "./helpers";
const App: Component = () => {
onMount(() => {
dispatch({ type: "FETCH_TIME_START" });
});
const onStop = () => {
dispatch({ type: "STOP_SERVER_START" });
};
const onLoad = () => {
dispatch({ type: "LOAD_GAME_START" });
};
const onSave = () => {
dispatch({ type: "SAVE_GAME_START" });
};
const onLoadAll = () => {
dispatch({ type: "FETCH_PLAYER_START" });
dispatch({ type: "FETCH_CAR_START" });
dispatch({ type: "FETCH_HOME_START" });
};
const moveItem = (id: number, source: AllInventories) => {
let destination: AllInventories = "player";
const random = Math.random();
if (random <= 0.25) {
destination = "player";
} else if (random <= 0.5) {
destination = "car";
} else if (random <= 0.75) {
destination = "home";
} else if (random <= 1.0) {
destination = "workbench";
}
dispatch({
type: "MOVE_INVENTORY_START",
payload: {
id: id,
source: source,
destination: destination,
},
});
};
return (
<div>
<p>Game Time: {state.game.time}</p>
<p>Player Name: {state.player.name}</p>
<br />
<p>Player Inventory:</p>
<div class="flex flex-row gap-1">
{state.player.inventory.items.map((item, index) => (
<div
class="w-24 h-24 bg-neutral-700"
onClick={() => moveItem(index, "player")}
>
{item.name}
</div>
))}
</div>
<br />
<p>Car Inventory:</p>
<div class="flex flex-row gap-1">
{state.car.inventory.items.map((item, index) => (
<div
class="w-24 h-24 bg-neutral-700"
onClick={() => moveItem(index, "car")}
>
{item.name}
</div>
))}
</div>
<br />
<p>Home Inventory:</p>
<div class="flex flex-row gap-1">
{state.home.inventory.items.map((item, index) => (
<div
class="w-24 h-24 bg-neutral-700"
onClick={() => moveItem(index, "home")}
>
{item.name}
</div>
))}
</div>
<br />
<p>Workbench Devices:</p>
<div class="flex flex-row gap-1">
{state.home.workbench.devices.map((item, index) => (
<div
class="w-24 h-24 bg-neutral-700"
onClick={() => moveItem(index, "workbench")}
>
{item.name}
</div>
))}
</div>
<br />
<div class="flex flex-col w-32 gap-1">
<button class="btn" onClick={onStop}>
Stop Server
</button>
<br />
<button class="btn" onClick={onLoad}>
Load Game
</button>
<br />
<button class="btn" onClick={onSave}>
Save Game
</button>
<br />
<button class="btn" onClick={onLoadAll}>
Test load all
</button>
</div>
</div>
);
};
export default App;

5
src/api/config.json Normal file
View file

@ -0,0 +1,5 @@
{
"schema": "http",
"url": "localhost",
"port": 2142
}

41
src/api/game/game.ts Normal file
View file

@ -0,0 +1,41 @@
import { callApi, HTTP } from "../tools";
import {
IGameCarResponse,
IGameHomeResponse,
IGamePlayerResponse,
IGameTimeResponse,
} from "./types";
async function fetchTimeApi(): Promise<IGameTimeResponse> {
const data = await callApi(HTTP.GET, "game/time");
return {
time: data,
};
}
async function fetchPlayerApi(): Promise<IGamePlayerResponse> {
const data = await callApi(HTTP.GET, "game/player");
return {
player: data,
};
}
async function fetchCarApi(): Promise<IGameCarResponse> {
const data = await callApi(HTTP.GET, "game/car");
return {
car: data,
};
}
async function fetchHomeApi(): Promise<IGameHomeResponse> {
const data = await callApi(HTTP.GET, "game/home");
return {
home: data,
};
}
export { fetchTimeApi, fetchPlayerApi, fetchCarApi, fetchHomeApi };

26
src/api/game/types.ts Normal file
View file

@ -0,0 +1,26 @@
import { ICarState } from "../../store/car";
import { IHomeState } from "../../store/home";
import { IPlayerState } from "../../store/player";
interface IGameTimeResponse {
time: number;
}
interface IGamePlayerResponse {
player: IPlayerState;
}
interface IGameCarResponse {
car: ICarState;
}
interface IGameHomeResponse {
home: IHomeState;
}
export {
type IGameTimeResponse,
type IGamePlayerResponse,
type IGameCarResponse,
type IGameHomeResponse,
};

View file

@ -0,0 +1,45 @@
import { callApi, HTTP } from "../tools";
import {
IInventoryCarResponse,
IInventoryHomeResponse,
IInventoryPlayerResponse,
IInventoryMoveRequest,
} from "./types";
async function fetchPlayerInventoryApi(): Promise<IInventoryPlayerResponse> {
const data = await callApi(HTTP.GET, "inventory/player");
return {
inventory: data,
};
}
async function fetchCarInventoryApi(): Promise<IInventoryCarResponse> {
const data = await callApi(HTTP.GET, "inventory/car");
return {
inventory: data,
};
}
async function fetchHomeInventoryApi(): Promise<IInventoryHomeResponse> {
const data = await callApi(HTTP.GET, "inventory/home");
return {
inventory: data,
};
}
async function moveInventoryApi(request: IInventoryMoveRequest) {
await callApi(HTTP.POST, `inventory/move/${request.id}`, {
source: request.source,
destination: request.destination,
});
}
export {
fetchPlayerInventoryApi,
fetchCarInventoryApi,
fetchHomeInventoryApi,
moveInventoryApi,
};

View file

@ -0,0 +1,27 @@
import { AllInventories } from "../../helpers";
import { IInventory } from "../../store/state/types";
interface IInventoryPlayerResponse {
inventory: IInventory;
}
interface IInventoryCarResponse {
inventory: IInventory;
}
interface IInventoryHomeResponse {
inventory: IInventory;
}
interface IInventoryMoveRequest {
id: number;
source: AllInventories;
destination: AllInventories;
}
export {
type IInventoryPlayerResponse,
type IInventoryCarResponse,
type IInventoryHomeResponse,
type IInventoryMoveRequest,
};

15
src/api/state/state.ts Normal file
View file

@ -0,0 +1,15 @@
import { callApi, HTTP } from "../tools";
async function stopServerApi() {
await callApi(HTTP.GET, "state/stop");
}
async function loadGameApi() {
await callApi(HTTP.GET, "state/load");
}
async function saveGameApi() {
await callApi(HTTP.GET, "state/save");
}
export { stopServerApi, loadGameApi, saveGameApi };

41
src/api/tools.ts Normal file
View file

@ -0,0 +1,41 @@
import config from "./config.json";
enum HTTP {
GET,
POST,
}
async function callApi(type: HTTP, path: string, body?: any) {
let response: Response;
switch (type) {
case HTTP.GET:
response = await fetch(
`${config.schema}://${config.url}:${config.port}/${path}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
},
);
break;
case HTTP.POST:
response = await fetch(
`${config.schema}://${config.url}:${config.port}/${path}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body ?? {}),
},
);
break;
}
const data = await response.json();
return data;
}
export { callApi, HTTP };

View file

@ -0,0 +1,12 @@
import { IItem } from "../../store/state/item";
import { IWorkbench } from "../../store/state/types";
interface IWorkbenchResponse {
workbench: IWorkbench;
}
interface IWorkbenchDevicesResponse {
devices: IItem[];
}
export { type IWorkbenchResponse, type IWorkbenchDevicesResponse };

View file

@ -0,0 +1,20 @@
import { callApi, HTTP } from "../tools";
import { IWorkbenchResponse, IWorkbenchDevicesResponse } from "./types";
async function fetchWorkbenchApi(): Promise<IWorkbenchResponse> {
const data = await callApi(HTTP.GET, "workbench");
return {
workbench: data,
};
}
async function fetchWorkbenchDevicesApi(): Promise<IWorkbenchDevicesResponse> {
const data = await callApi(HTTP.GET, "workbench/devices");
return {
devices: data,
};
}
export { fetchWorkbenchApi, fetchWorkbenchDevicesApi };

3
src/consts.ts Normal file
View file

@ -0,0 +1,3 @@
const WORKBENCH_SIZE = 999;
export { WORKBENCH_SIZE };

3
src/helpers.ts Normal file
View file

@ -0,0 +1,3 @@
type AllInventories = "player" | "car" | "home" | "workbench";
export { type AllInventories };

2
src/index.css Normal file
View file

@ -0,0 +1,2 @@
@import "tailwindcss";
@plugin "daisyui";

16
src/index.tsx Normal file
View file

@ -0,0 +1,16 @@
/* @refresh reload */
import './index.css';
import { render } from 'solid-js/web';
import 'solid-devtools';
import App from './App';
const root = document.getElementById('root');
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
throw new Error(
'Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?',
);
}
render(() => <App />, root!);

23
src/services/car/car.ts Normal file
View file

@ -0,0 +1,23 @@
import { fetchCarApi } from "../../api/game/game";
import { fetchCarInventoryApi } from "../../api/inventory/inventory";
import { dispatch } from "../../store/state";
async function fetchCar() {
const data = await fetchCarApi();
dispatch({
type: "FETCH_CAR_FINISH",
payload: data.car,
});
}
async function fetchCarInventory() {
const data = await fetchCarInventoryApi();
dispatch({
type: "FETCH_CAR_INVENTORY_FINISH",
payload: data.inventory,
});
}
export { fetchCar, fetchCarInventory };

55
src/services/game/game.ts Normal file
View file

@ -0,0 +1,55 @@
import { fetchTimeApi } from "../../api/game/game";
import { moveInventoryApi } from "../../api/inventory/inventory";
import { IInventoryMoveRequest } from "../../api/inventory/types";
import { loadGameApi, saveGameApi, stopServerApi } from "../../api/state/state";
import { dispatch } from "../../store/state";
async function stopServer() {
await stopServerApi();
dispatch({ type: "STOP_SERVER_FINISH" });
}
async function loadGame() {
await loadGameApi();
dispatch({ type: "LOAD_GAME_FINISH" });
dispatch({ type: "FETCH_TIME_START" });
}
async function saveGame() {
await saveGameApi();
dispatch({ type: "SAVE_GAME_FINISH" });
}
async function fetchTime() {
const data = await fetchTimeApi();
dispatch({
type: "FETCH_TIME_FINISH",
payload: data.time,
});
}
async function moveInventory(payload: IInventoryMoveRequest) {
await moveInventoryApi(payload);
dispatch({
type: "MOVE_INVENTORY_FINISH",
});
dispatch({
type: "FETCH_PLAYER_INVENTORY_START",
});
dispatch({
type: "FETCH_CAR_INVENTORY_START",
});
dispatch({
type: "FETCH_HOME_INVENTORY_START",
});
dispatch({
type: "FETCH_HOME_WORKBENCH_DEVICES_START",
});
}
export { stopServer, loadGame, saveGame, fetchTime, moveInventory };

50
src/services/home/home.ts Normal file
View file

@ -0,0 +1,50 @@
import { fetchHomeApi } from "../../api/game/game";
import { fetchHomeInventoryApi } from "../../api/inventory/inventory";
import {
fetchWorkbenchApi,
fetchWorkbenchDevicesApi,
} from "../../api/workbench/workbench";
import { dispatch } from "../../store/state";
async function fetchHome() {
const data = await fetchHomeApi();
dispatch({
type: "FETCH_HOME_FINISH",
payload: data.home,
});
}
async function fetchHomeInventory() {
const data = await fetchHomeInventoryApi();
dispatch({
type: "FETCH_HOME_INVENTORY_FINISH",
payload: data.inventory,
});
}
async function fetchHomeWorkbench() {
const data = await fetchWorkbenchApi();
dispatch({
type: "FETCH_HOME_WORKBENCH_FINISH",
payload: data.workbench,
});
}
async function fetchHomeWorkbenchDevices() {
const data = await fetchWorkbenchDevicesApi();
dispatch({
type: "FETCH_HOME_WORKBENCH_DEVICES_FINISH",
payload: data.devices,
});
}
export {
fetchHome,
fetchHomeInventory,
fetchHomeWorkbench,
fetchHomeWorkbenchDevices,
};

View file

@ -0,0 +1,23 @@
import { fetchPlayerApi } from "../../api/game/game";
import { fetchPlayerInventoryApi } from "../../api/inventory/inventory";
import { dispatch } from "../../store/state";
async function fetchPlayer() {
const data = await fetchPlayerApi();
dispatch({
type: "FETCH_PLAYER_FINISH",
payload: data.player,
});
}
async function fetchPlayerInventory() {
const data = await fetchPlayerInventoryApi();
dispatch({
type: "FETCH_PLAYER_INVENTORY_FINISH",
payload: data.inventory,
});
}
export { fetchPlayer, fetchPlayerInventory };

21
src/store/actions.ts Normal file
View file

@ -0,0 +1,21 @@
import { CarAction, CarActionTypes } from "./car";
import { GameAction, GameActionTypes } from "./game";
import { HomeAction, HomeActionTypes } from "./home";
import { LoadingAction, LoadingActionTypes } from "./loading";
import { PlayerAction, PlayerActionTypes } from "./player";
type ActionTypes =
| LoadingActionTypes
| GameActionTypes
| PlayerActionTypes
| HomeActionTypes
| CarActionTypes;
type Action =
| LoadingAction
| GameAction
| PlayerAction
| HomeAction
| CarAction;
export { type Action, type ActionTypes };

21
src/store/car/actions.ts Normal file
View file

@ -0,0 +1,21 @@
import { IInventory } from "../state/types";
import { ICarState } from "./state";
type FETCH_CAR_START = "FETCH_CAR_START";
type FETCH_CAR_FINISH = "FETCH_CAR_FINISH";
type FETCH_CAR_INVENTORY_START = "FETCH_CAR_INVENTORY_START";
type FETCH_CAR_INVENTORY_FINISH = "FETCH_CAR_INVENTORY_FINISH";
type CarActionTypes =
| FETCH_CAR_START
| FETCH_CAR_FINISH
| FETCH_CAR_INVENTORY_START
| FETCH_CAR_INVENTORY_FINISH;
type CarAction =
| { type: FETCH_CAR_START }
| { type: FETCH_CAR_FINISH; payload: ICarState }
| { type: FETCH_CAR_INVENTORY_START }
| { type: FETCH_CAR_INVENTORY_FINISH; payload: IInventory };
export { type CarActionTypes, type CarAction };

28
src/store/car/car.ts Normal file
View file

@ -0,0 +1,28 @@
import { fetchCar, fetchCarInventory } from "../../services/car/car";
import { CarAction } from "./actions";
import { ICarState } from "./state";
function carReducer(state: ICarState, action: CarAction): ICarState {
switch (action.type) {
case "FETCH_CAR_START":
fetchCar();
return state;
case "FETCH_CAR_FINISH":
return {
...state,
inventory: action.payload.inventory,
};
case "FETCH_CAR_INVENTORY_START":
fetchCarInventory();
return state;
case "FETCH_CAR_INVENTORY_FINISH":
return {
...state,
inventory: action.payload,
};
default:
return state;
}
}
export { carReducer };

3
src/store/car/index.ts Normal file
View file

@ -0,0 +1,3 @@
export * from "./actions";
export * from "./state";
export * from "./car";

7
src/store/car/state.ts Normal file
View file

@ -0,0 +1,7 @@
import { IInventory } from "../state/types";
interface ICarState {
inventory: IInventory;
}
export { type ICarState };

38
src/store/game/actions.ts Normal file
View file

@ -0,0 +1,38 @@
import { IInventoryMoveRequest } from "../../api/inventory/types";
type STOP_SERVER_START = "STOP_SERVER_START";
type STOP_SERVER_FINISH = "STOP_SERVER_FINISH";
type LOAD_GAME_START = "LOAD_GAME_START";
type LOAD_GAME_FINISH = "LOAD_GAME_FINISH";
type SAVE_GAME_START = "SAVE_GAME_START";
type SAVE_GAME_FINISH = "SAVE_GAME_FINISH";
type FETCH_TIME_START = "FETCH_TIME_START";
type FETCH_TIME_FINISH = "FETCH_TIME_FINISH";
type MOVE_INVENTORY_START = "MOVE_INVENTORY_START";
type MOVE_INVENTORY_FINISH = "MOVE_INVENTORY_FINISH";
type GameActionTypes =
| STOP_SERVER_START
| STOP_SERVER_FINISH
| LOAD_GAME_START
| LOAD_GAME_FINISH
| SAVE_GAME_START
| SAVE_GAME_FINISH
| FETCH_TIME_START
| FETCH_TIME_FINISH
| MOVE_INVENTORY_START
| MOVE_INVENTORY_FINISH;
type GameAction =
| { type: STOP_SERVER_START }
| { type: STOP_SERVER_FINISH }
| { type: LOAD_GAME_START }
| { type: LOAD_GAME_FINISH }
| { type: SAVE_GAME_START }
| { type: SAVE_GAME_FINISH }
| { type: FETCH_TIME_START }
| { type: FETCH_TIME_FINISH; payload: number }
| { type: MOVE_INVENTORY_START; payload: IInventoryMoveRequest }
| { type: MOVE_INVENTORY_FINISH };
export { type GameActionTypes, type GameAction };

43
src/store/game/game.ts Normal file
View file

@ -0,0 +1,43 @@
import {
fetchTime,
loadGame,
moveInventory,
saveGame,
stopServer,
} from "../../services/game/game";
import { GameAction } from "./actions";
import { IGameState } from "./state";
function gameReducer(state: IGameState, action: GameAction): IGameState {
switch (action.type) {
case "STOP_SERVER_START":
stopServer();
return { ...state, stopping: true };
case "STOP_SERVER_FINISH":
return { ...state, stopping: false };
case "LOAD_GAME_START":
loadGame();
return { ...state, loading: true };
case "LOAD_GAME_FINISH":
return { ...state, loading: false };
case "SAVE_GAME_START":
saveGame();
return { ...state, saving: true };
case "SAVE_GAME_FINISH":
return { ...state, saving: false };
case "FETCH_TIME_START":
fetchTime();
return { ...state, stopping: true };
case "FETCH_TIME_FINISH":
return { ...state, time: action.payload };
case "MOVE_INVENTORY_START":
moveInventory(action.payload);
return state;
case "MOVE_INVENTORY_FINISH":
return state;
default:
return state;
}
}
export { gameReducer };

3
src/store/game/index.ts Normal file
View file

@ -0,0 +1,3 @@
export * from "./actions";
export * from "./state";
export * from "./game";

8
src/store/game/state.ts Normal file
View file

@ -0,0 +1,8 @@
interface IGameState {
stopping: boolean;
loading: boolean;
saving: boolean;
time: number;
}
export { type IGameState };

41
src/store/home/actions.ts Normal file
View file

@ -0,0 +1,41 @@
import { IItem } from "../state/item";
import { IInventory, IWorkbench } from "../state/types";
import { IHomeState } from "./state";
type FETCH_HOME_START = "FETCH_HOME_START";
type FETCH_HOME_FINISH = "FETCH_HOME_FINISH";
type FETCH_HOME_INVENTORY_START = "FETCH_HOME_INVENTORY_START";
type FETCH_HOME_INVENTORY_FINISH = "FETCH_HOME_INVENTORY_FINISH";
type FETCH_HOME_WORKBENCH_START = "FETCH_HOME_WORKBENCH_START";
type FETCH_HOME_WORKBENCH_FINISH = "FETCH_HOME_WORKBENCH_FINISH";
type FETCH_HOME_WORKBENCH_DEVICES_START = "FETCH_HOME_WORKBENCH_DEVICES_START";
type FETCH_HOME_WORKBENCH_DEVICES_FINISH =
"FETCH_HOME_WORKBENCH_DEVICES_FINISH";
type HomeActionTypes =
| FETCH_HOME_START
| FETCH_HOME_FINISH
| FETCH_HOME_INVENTORY_START
| FETCH_HOME_INVENTORY_FINISH
| FETCH_HOME_WORKBENCH_START
| FETCH_HOME_WORKBENCH_FINISH
| FETCH_HOME_WORKBENCH_DEVICES_START
| FETCH_HOME_WORKBENCH_DEVICES_FINISH;
type HomeAction =
| { type: FETCH_HOME_START }
| { type: FETCH_HOME_FINISH; payload: IHomeState }
| { type: FETCH_HOME_INVENTORY_START }
| { type: FETCH_HOME_INVENTORY_FINISH; payload: IInventory }
| { type: FETCH_HOME_WORKBENCH_START }
| {
type: FETCH_HOME_WORKBENCH_FINISH;
payload: IWorkbench;
}
| { type: FETCH_HOME_WORKBENCH_DEVICES_START }
| {
type: FETCH_HOME_WORKBENCH_DEVICES_FINISH;
payload: IItem[];
};
export { type HomeActionTypes, type HomeAction };

54
src/store/home/home.ts Normal file
View file

@ -0,0 +1,54 @@
import {
fetchHome,
fetchHomeInventory,
fetchHomeWorkbench,
fetchHomeWorkbenchDevices,
} from "../../services/home/home";
import { HomeAction } from "./actions";
import { IHomeState } from "./state";
function homeReducer(state: IHomeState, action: HomeAction): IHomeState {
switch (action.type) {
case "FETCH_HOME_START":
fetchHome();
return state;
case "FETCH_HOME_FINISH":
return {
...state,
inventory: action.payload.inventory,
workbench: action.payload.workbench,
modem: action.payload.modem,
};
case "FETCH_HOME_INVENTORY_START":
fetchHomeInventory();
return state;
case "FETCH_HOME_INVENTORY_FINISH":
return {
...state,
inventory: action.payload,
};
case "FETCH_HOME_WORKBENCH_START":
fetchHomeWorkbench();
return state;
case "FETCH_HOME_WORKBENCH_FINISH":
return {
...state,
workbench: action.payload,
};
case "FETCH_HOME_WORKBENCH_DEVICES_START":
fetchHomeWorkbenchDevices();
return state;
case "FETCH_HOME_WORKBENCH_DEVICES_FINISH":
return {
...state,
workbench: {
...state.workbench,
devices: action.payload,
},
};
default:
return state;
}
}
export { homeReducer };

3
src/store/home/index.ts Normal file
View file

@ -0,0 +1,3 @@
export * from "./actions";
export * from "./state";
export * from "./home";

10
src/store/home/state.ts Normal file
View file

@ -0,0 +1,10 @@
import { IModem } from "../state/item";
import { IInventory, IWorkbench } from "../state/types";
interface IHomeState {
inventory: IInventory;
workbench: IWorkbench;
modem?: IModem;
}
export { type IHomeState };

View file

@ -0,0 +1,12 @@
type LOADING_START = "LOADING_START";
type LOADING_SUCCESS = "LOADING_SUCCESS";
type LOADING_ERROR = "LOADING_ERROR";
type LoadingActionTypes = LOADING_START | LOADING_SUCCESS | LOADING_ERROR;
type LoadingAction =
| { type: LOADING_START }
| { type: LOADING_SUCCESS }
| { type: LOADING_ERROR; payload: string };
export { type LoadingActionTypes, type LoadingAction };

View file

@ -0,0 +1,3 @@
export * from "./actions";
export * from "./state";
export * from "./loading";

View file

@ -0,0 +1,20 @@
import { LoadingAction } from "./actions";
import { ILoadingState } from "./state";
function loadingReducer(
state: ILoadingState,
action: LoadingAction,
): ILoadingState {
switch (action.type) {
case "LOADING_START":
return { ...state, status: true };
case "LOADING_SUCCESS":
return { ...state, status: false };
case "LOADING_ERROR":
return { ...state, status: false, error: "test" };
default:
return state;
}
}
export { loadingReducer };

View file

@ -0,0 +1,6 @@
interface ILoadingState {
status: boolean;
error?: string;
}
export { type ILoadingState };

View file

@ -0,0 +1,24 @@
import { IInventory } from "../state/types";
import { IPlayerState } from "./state";
type FETCH_PLAYER_START = "FETCH_PLAYER_START";
type FETCH_PLAYER_FINISH = "FETCH_PLAYER_FINISH";
type FETCH_PLAYER_INVENTORY_START = "FETCH_PLAYER_INVENTORY_START";
type FETCH_PLAYER_INVENTORY_FINISH = "FETCH_PLAYER_INVENTORY_FINISH";
type PlayerActionTypes =
| FETCH_PLAYER_START
| FETCH_PLAYER_FINISH
| FETCH_PLAYER_INVENTORY_START
| FETCH_PLAYER_INVENTORY_FINISH;
type PlayerAction =
| { type: FETCH_PLAYER_START }
| { type: FETCH_PLAYER_FINISH; payload: IPlayerState }
| { type: FETCH_PLAYER_INVENTORY_START }
| {
type: FETCH_PLAYER_INVENTORY_FINISH;
payload: IInventory;
};
export { type PlayerActionTypes, type PlayerAction };

View file

@ -0,0 +1,3 @@
export * from "./actions";
export * from "./state";
export * from "./player";

View file

@ -0,0 +1,36 @@
import {
fetchPlayer,
fetchPlayerInventory,
} from "../../services/player/player";
import { PlayerAction } from "./actions";
import { IPlayerState } from "./state";
function playerReducer(
state: IPlayerState,
action: PlayerAction,
): IPlayerState {
switch (action.type) {
case "FETCH_PLAYER_START":
fetchPlayer();
return state;
case "FETCH_PLAYER_FINISH":
return {
...state,
name: action.payload.name,
inventory: action.payload.inventory,
location: action.payload.location,
};
case "FETCH_PLAYER_INVENTORY_START":
fetchPlayerInventory();
return state;
case "FETCH_PLAYER_INVENTORY_FINISH":
return {
...state,
inventory: action.payload,
};
default:
return state;
}
}
export { playerReducer };

10
src/store/player/state.ts Normal file
View file

@ -0,0 +1,10 @@
import { Location } from "../state/location";
import { IInventory } from "../state/types";
interface IPlayerState {
name: string;
inventory: IInventory;
location: Location;
}
export { type IPlayerState };

19
src/store/reducers.ts Normal file
View file

@ -0,0 +1,19 @@
import { IState } from "./types";
import { Action } from "./actions";
import { LoadingAction, loadingReducer } from "./loading";
import { GameAction, gameReducer } from "./game";
import { PlayerAction, playerReducer } from "./player";
import { HomeAction, homeReducer } from "./home";
import { CarAction, carReducer } from "./car";
function reducer(state: IState, action: Action): IState {
return {
loading: loadingReducer(state.loading, action as LoadingAction),
game: gameReducer(state.game, action as GameAction),
player: playerReducer(state.player, action as PlayerAction),
home: homeReducer(state.home, action as HomeAction),
car: carReducer(state.car, action as CarAction),
};
}
export { reducer };

52
src/store/state.ts Normal file
View file

@ -0,0 +1,52 @@
import { createStore } from "solid-js/store";
import { IState } from "./types";
import { Action } from "./actions";
import { reducer } from "./reducers";
import { Location } from "./state/location";
const [state, setState] = createStore<IState>({
loading: {
status: true,
error: undefined,
},
game: {
stopping: false,
loading: false,
saving: false,
time: 0,
},
player: {
name: "",
inventory: {
size: 0,
items: [],
},
location: Location.PLAYER_HOME,
},
home: {
inventory: {
size: 0,
items: [],
},
workbench: {
devices: [],
},
modem: undefined,
},
car: {
inventory: {
size: 0,
items: [],
},
},
});
function dispatch(action: Action) {
setState(reducer(state, action));
}
async function dispatchAsync(action: Action) {
setState(reducer(state, action));
}
export { state, setState, dispatch };

View file

@ -0,0 +1,59 @@
enum Company {
Intel,
AMD,
Nvidia,
Seagate,
WD,
GSkill,
NZXT,
EK,
Alphacool,
EVGA,
Kingston,
Motorola,
Nikon,
Canon,
Qualcomm,
TSMC,
Samsung,
Apple,
Microsoft,
Canonical,
Amazon,
Meta,
Google,
HP,
Lenovo,
Vivo,
Huawei,
Cisco,
Asus,
Acer,
Sony,
LG,
HTC,
OnePlus,
Xiaomi,
Gigabyte,
Nokia,
HMD,
DELL,
FrameWork,
Tencent,
RODE,
RME,
Fiio,
Sennheiser,
Beyerdynamic,
Audeze,
Pine64,
Nintendo,
Nubia,
ZTE,
Nothing,
Essential,
Fairphone,
Razer,
}
export { Company };

View file

@ -0,0 +1,31 @@
enum ConnectorType {
USB1,
USB2,
USB3,
USB4,
USBC1,
USBC2,
USBC3,
USBC4,
MOLEX,
SATA_POWER,
SATA1,
SATA2,
SATA3,
AGP,
PCI_POWER_4,
PCI_POWER_6,
PCI_POWER_8,
PCI,
PCIE,
PCIE2,
PCIE3,
PCIE4,
PCIE5,
PCIE6,
PCIE7,
PCIE8,
PCIE9,
}
export { ConnectorType };

34
src/store/state/cpu.ts Normal file
View file

@ -0,0 +1,34 @@
enum CPUArchitecture {
M_6502,
M_6800,
M_6809,
M_680X0,
I_8080,
I_8051,
Z80,
SPARC,
MIPS,
POWER_PC,
x86,
x86_64,
Itanium,
ARMv7,
ARMv8,
ARMv9,
RISC_V,
LoongArch,
}
enum CPUFeatures {
AVX,
AVX2,
AVX512,
}
enum SocketType {
INTEL_LGA_1155,
INTEL_LGA_1156,
INTEL_LGA_2011,
}
export { CPUArchitecture, CPUFeatures, SocketType };

39
src/store/state/gpu.ts Normal file
View file

@ -0,0 +1,39 @@
enum GPUArchitecture {
Fahrenheit,
Celsius,
Kelvin,
Rankine,
Curie,
Tesla,
Fermi,
Kepler,
Maxwell,
Maxwell2,
Pascal,
Turing,
Volta,
Ampere,
Lovelace,
Hopper,
Blackwell,
Rubin,
TeraScale,
TeraScale2,
TeraScale3,
CGN,
CGN2,
CGN3,
CGN4,
CGN5,
RDNA,
RDNA2,
RDNA3,
RDNA3_5,
RDNA4,
CDNA,
CDNA2,
CDNA3,
UDNA,
}
export { GPUArchitecture };

214
src/store/state/item.ts Normal file
View file

@ -0,0 +1,214 @@
import type { Company } from "./company.js";
import type { ConnectorType } from "./connector.js";
import type { SocketType } from "./cpu.js";
import type { MemoryType } from "./memory.js";
import type { DiscType, DiskType, IStorage } from "./storage.js";
import type { INet } from "./types.js";
enum ItemType {
SCREWDRIVER,
CPU,
GRAPHIC_CARD,
RAM_MODULE,
DISK,
DISC,
TAPE,
VHS,
DISKETTE,
CASE,
PSU,
MOTHERBOARD,
FAN,
CPU_COOLER,
GPU_COOLER,
NETWORK_CARD,
SOUND_CARD,
NETWORK_SWITCH,
WIFI_AP,
ROUTER,
MODEM,
MONITOR,
KEYBOARD,
MOUSE,
JOYSTICK,
HEADPHONES,
DAC,
MICROPHONE,
CAMERA,
PHONE,
LAPTOP,
COMPUTER,
SECURITY_KEY,
}
enum FormFactorType {
M_ATX,
ATX,
E_ATX,
}
interface IItem {
type: ItemType;
name: string;
durability: number;
manufacturer?: Company | "Player";
availability?: number;
rarity?: number;
price?: number;
canFitInComputerCase?: boolean;
canFitInLaptopCase?: boolean;
canFitInMobileCase?: boolean;
}
interface IConnectedDevice extends IItem {
connector: ConnectorType;
}
interface IScrewdriver extends IItem {
quality: number;
}
interface ICPUCore {
originalClockSpeed: number;
clockSpeed: number;
threads: number;
cacheL1?: number;
cacheL2?: number;
}
interface ICPU extends IItem {
cores: ICPUCore[];
cacheL3?: number;
cacheL4?: number;
gpu?: IGPU;
npu?: INPU;
tdp: number;
process: number;
socket: SocketType;
}
interface IGPU extends IItem {
originalClockSpeed: number;
clockSpeed: number;
coreCount: number;
shadingUnitCount: number;
tmuCount: number;
ropCount: number;
tensorCoreCount: number;
rtCoreCount: number;
cacheL0?: number;
cacheL1?: number;
cacheL2?: number;
cacheL3?: number;
tops: number;
pixelRate: number;
textureRate: number;
fp16flops: number;
fp32flops: number;
fp64flops: number;
features: IGPUFeatures;
process: number;
}
interface INPU extends IItem {
tops: number;
}
interface IGPUFeatures {
directxVersion?: number;
openglVersion?: number;
openclVersion?: number;
vulkanVersion?: number;
cudaVersion?: number;
shaderModel?: number;
}
interface IGraphicsCard extends IConnectedDevice {
gpu: IGPU;
memory: IGraphicsCardMemory;
tdp: number;
}
interface IGraphicsCardMemory {
type: MemoryType;
originalClockSpeed: number;
clockSpeed: number;
busWidth: number;
bandwidth: number;
capacity: number;
}
interface IRAMModule extends IItem {
memoryType: MemoryType;
originalClockSpeed: number;
clockSpeed: number;
capacity: number;
tdp: number;
}
interface IDisk extends IConnectedDevice {
diskType: DiskType;
bandwidth: number;
capacity: number;
tdp: number;
storage: IStorage;
}
interface IDisc extends IItem {
discType: DiscType;
bandwidth: number;
capacity: number;
storage: IStorage;
}
interface ICase extends IItem {
formFactor: FormFactorType;
width: number;
height: number;
depth: number;
installedDevices: IItem[];
}
interface IPSU extends IItem {
formFactor: FormFactorType;
width: number;
height: number;
depth: number;
wattage: number;
connectors: ConnectorType[];
}
interface IMotherboard extends IItem {
formFactor: FormFactorType;
connectors: ConnectorType[];
socket: SocketType;
socketCount: number;
memoryType: MemoryType;
memorySlots: number;
installedCPUs: ICPU[];
installedRAMs: IRAMModule[];
installedDevices: IConnectedDevice[];
}
interface IModem extends IItem {
bandwidth: number;
net: INet;
}
export {
ItemType,
FormFactorType,
type IItem,
type IConnectedDevice,
type IScrewdriver,
type ICPU,
type IGPU,
type IGraphicsCard,
type IRAMModule,
type IDisk,
type IDisc,
type ICase,
type IPSU,
type IMotherboard,
type IModem,
};

View file

@ -0,0 +1,7 @@
enum Location {
PLAYER_HOME,
PLAYER_CAR,
LOCAL_STORE,
}
export { Location };

53
src/store/state/memory.ts Normal file
View file

@ -0,0 +1,53 @@
enum MemoryType {
DDR,
LPDDR,
LPDDRX,
DDR2,
LPDDR2,
LPDDR2X,
DDR3,
LPDDR3,
LPDDR3X,
DDR4,
LPDDR4,
LPDDR4X,
DDR5,
LPDDR5,
LPDDR5X,
DDR6,
LPDDR6,
LPDDR6X,
DDR7,
LPDDR7,
LPDDR7X,
DDR8,
LPDDR8,
LPDDR8X,
DDR9,
LPDDR9,
LPDDR9X,
GDDR1,
GDDR1X,
GDDR2,
GDDR2X,
GDDR3,
GDDR3X,
GDDR4,
GDDR4X,
GDDR5,
GDDR5X,
GDDR6,
GDDR6X,
GDDR7,
GDDR7X,
GDDR8,
GDDR8X,
GDDR9,
GDDR9X,
HBM,
HBM2,
HBM3,
HBM4,
}
export { MemoryType };

View file

@ -0,0 +1,6 @@
enum MotherboardFeatures {
BIOS,
UEFI,
}
export { MotherboardFeatures };

View file

@ -0,0 +1,13 @@
enum SoftwareType {
OS,
}
interface ISoftware {
type: SoftwareType;
name: string;
cpuUsage: number;
memoryUsage: number;
storageUsage: number;
}
export { SoftwareType, type ISoftware };

View file

@ -0,0 +1,57 @@
import type { ISoftware } from "./software.js";
enum DiskType {
HDD,
SSD,
Flash,
}
enum DiscType {
LaserDisc,
CD,
DVD,
BluRay,
}
enum FilesystemType {
EXT,
EXT2,
EXT3,
EXT4,
FAT16,
FAT32,
NTFS,
EXFAT,
}
interface IStorage {
filesystem: IFileSystem;
}
interface IFileSystem {
type: FilesystemType;
rootDirectory: IDirectory;
}
interface IDirectory {
name: string;
directories: IDirectory[];
files: IFile[];
}
interface IFile {
name: string;
size: string;
isSoftware: boolean;
contents: string | ISoftware;
}
export {
DiskType,
DiscType,
FilesystemType,
type IStorage,
type IFileSystem,
type IDirectory,
type IFile,
};

38
src/store/state/types.ts Normal file
View file

@ -0,0 +1,38 @@
import type { IItem, IModem } from "./item.js";
import type { Location } from "./location.js";
interface IInventory {
size: number;
items: IItem[];
}
interface IWorkbench {
devices: IItem[];
}
interface IWebsite {
name: string;
ip: string;
domain: string;
html: string;
}
interface INet {
ip?: string;
}
interface IShop {
name: string;
items: IItem[];
}
export {
type IPlayer,
type ICar,
type IHome,
type IInventory,
type IWorkbench,
type IWebsite,
type INet,
type IShop,
};

15
src/store/types.ts Normal file
View file

@ -0,0 +1,15 @@
import { ICarState } from "./car";
import { IGameState } from "./game";
import { IHomeState } from "./home";
import { ILoadingState } from "./loading";
import { IPlayerState } from "./player";
interface IState {
loading: ILoadingState;
game: IGameState;
player: IPlayerState;
home: IHomeState;
car: ICarState;
}
export { type IState };

20
tsconfig.json Normal file
View file

@ -0,0 +1,20 @@
{
"compilerOptions": {
// General
"jsx": "preserve",
"jsxImportSource": "solid-js",
"target": "ESNext",
// Modules
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"isolatedModules": true,
"module": "ESNext",
"moduleResolution": "bundler",
"noEmit": true,
// Type Checking & Safety
"strict": true,
"types": ["vite/client"]
}
}

13
vite.config.ts Normal file
View file

@ -0,0 +1,13 @@
import { defineConfig } from "vite";
import tailwindcss from "@tailwindcss/vite";
import solidPlugin from "vite-plugin-solid";
export default defineConfig({
plugins: [tailwindcss(), solidPlugin()],
server: {
port: 3000,
},
build: {
target: "esnext",
},
});