feat: Rebrand 'Instance' to 'Cluster'

This commit is contained in:
LynithDev 2024-03-28 21:12:32 +01:00
parent e607dfe6b6
commit 0dd1365fa4
14 changed files with 123 additions and 129 deletions

View file

@ -32,7 +32,7 @@ pub struct Manifest {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Instance {
pub struct Cluster {
pub id: Uuid,
pub created_at: DateTime<Local>,
pub name: String,
@ -57,17 +57,17 @@ impl ClientType {
pub fn get_impl<'a>(
client: &'a ClientType,
instance: &'a Instance,
cluster: &'a Cluster,
manifest: &'a Manifest,
) -> Box<dyn ClientTrait<'a> + 'a> {
Box::new(match client {
ClientType::Vanilla(_) => vanilla::VanillaClient::new(instance, manifest),
ClientType::Vanilla(_) => vanilla::VanillaClient::new(cluster, manifest),
})
}
#[async_trait]
pub trait ClientTrait<'a>: Send + Sync {
fn new(instance: &'a Instance, manifest: &'a Manifest) -> Self
fn new(cluster: &'a Cluster, manifest: &'a Manifest) -> Self
where
Self: Sized;
@ -79,9 +79,10 @@ pub trait ClientTrait<'a>: Send + Sync {
async fn install_natives(&self) -> crate::Result<()>;
async fn install_assets(&self) -> crate::Result<()>;
fn get_instance(&self) -> &'a Instance
fn get_cluster(&self) -> &'a Cluster
where
Self: Sized;
fn get_manifest(&self) -> &'a Manifest
where
Self: Sized;
@ -97,7 +98,7 @@ macro_rules! create_game_client {
#[derive(Debug, Clone)]
pub struct $client<'a> {
pub instance: &'a crate::game::client::Instance,
pub cluster: &'a crate::game::client::Cluster,
pub manifest: &'a crate::game::client::Manifest,
$(pub $name: $type),*
}
@ -107,11 +108,11 @@ macro_rules! create_game_client {
#[macro_export]
macro_rules! impl_game_client {
() => {
fn get_instance(&self) -> &'a crate::game::client::Instance
fn get_cluster(&self) -> &'a crate::game::client::Cluster
where
Self: Sized,
{
self.instance
self.cluster
}
fn get_manifest(&self) -> &'a crate::game::client::Manifest
@ -125,54 +126,54 @@ macro_rules! impl_game_client {
#[derive(Debug, thiserror::Error)]
pub enum ClientManagerError {
#[error("Instance not found")]
InstanceNotFound,
#[error("Cluster not found")]
ClusterNotFound,
#[error("Manifest not found")]
ManifestNotFound,
}
pub struct ClientManager {
instances: HashMap<Uuid, Instance>,
clusters: HashMap<Uuid, Cluster>,
manifests: HashMap<Uuid, Manifest>,
}
impl ClientManager {
pub fn new() -> crate::Result<Self> {
let instances = load_and_serialize::<Instance>(&dirs::instances_dir()?)?;
let clusters = load_and_serialize::<Cluster>(&dirs::clusters_dir()?)?;
let manifests = load_and_serialize::<Manifest>(&dirs::manifests_dir()?)?;
Ok(Self {
instances,
clusters,
manifests,
})
}
pub fn get_impl_uuid<'a>(&'a self, uuid: Uuid) -> crate::Result<Box<dyn ClientTrait<'a> + 'a>> {
let instance = self.get_instance(uuid)?;
let cluster = self.get_cluster(uuid)?;
let manifest = self.get_manifest(uuid)?;
Ok(get_impl(&instance.client, &instance, &manifest))
Ok(get_impl(&cluster.client, &cluster, &manifest))
}
pub fn get_instances(&self) -> Vec<&Instance> {
self.instances.values().collect()
pub fn get_clusters(&self) -> Vec<&Cluster> {
self.clusters.values().collect()
}
pub fn get_instances_owned(&self) -> Vec<Instance> {
self.instances.values().cloned().collect()
pub fn get_clusters_owned(&self) -> Vec<Cluster> {
self.clusters.values().cloned().collect()
}
pub fn get_instance(&self, uuid: Uuid) -> crate::Result<&Instance> {
self.instances
pub fn get_cluster(&self, uuid: Uuid) -> crate::Result<&Cluster> {
self.clusters
.get(&uuid)
.ok_or(ClientManagerError::InstanceNotFound.into())
.ok_or(ClientManagerError::ClusterNotFound.into())
}
pub fn get_instance_mut(&mut self, uuid: Uuid) -> crate::Result<&mut Instance> {
self.instances
pub fn get_cluster_mut(&mut self, uuid: Uuid) -> crate::Result<&mut Cluster> {
self.clusters
.get_mut(&uuid)
.ok_or(ClientManagerError::InstanceNotFound.into())
.ok_or(ClientManagerError::ClusterNotFound.into())
}
pub fn get_manifest(&self, uuid: Uuid) -> crate::Result<&Manifest> {
@ -187,7 +188,7 @@ impl ClientManager {
.ok_or(ClientManagerError::ManifestNotFound.into())
}
pub async fn create_instance(
pub async fn create_cluster(
&mut self,
name: String,
version: String,
@ -218,8 +219,8 @@ impl ClientManager {
)?;
self.manifests.insert(uuid, manifest);
// Save the instance
let instance = Instance {
// Save the cluster
let cluster = Cluster {
id: uuid,
created_at: Local::now(),
name,
@ -229,10 +230,10 @@ impl ClientManager {
};
save(
&dirs::instances_dir()?.join(format!("{}.json", uuid)),
&instance,
&dirs::clusters_dir()?.join(format!("{}.json", uuid)),
&cluster,
)?;
self.instances.insert(uuid, instance);
self.clusters.insert(uuid, cluster);
Ok(uuid)
}
@ -292,7 +293,7 @@ where
let parsed = match serde_json::from_str::<T>(&content) {
Ok(parsed) => parsed,
Err(_) => {
eprintln!("Couldn't parse file content as JSON: '{:?}'", content);
eprintln!("Couldn't parse file '{}' content as JSON", path.display());
continue;
}
};

View file

@ -1,5 +1,5 @@
use super::{
client::{ClientTrait, Instance, Manifest, Version},
client::{ClientTrait, Cluster, Manifest, Version},
minecraft::MinecraftManifest,
};
use crate::{
@ -22,8 +22,8 @@ create_game_client! {
impl<'a> ClientTrait<'a> for VanillaClient<'a> {
impl_game_client!();
fn new(instance: &'a Instance, manifest: &'a Manifest) -> Self {
VanillaClient { instance, manifest }
fn new(cluster: &'a Cluster, manifest: &'a Manifest) -> Self {
VanillaClient { cluster, manifest }
}
async fn launch(&self) -> crate::Result<()> {

View file

@ -22,8 +22,8 @@ pub fn java_dir() -> crate::Result<PathBuf> {
Ok(app_config_dir()?.join("java"))
}
pub fn instances_dir() -> crate::Result<PathBuf> {
Ok(app_config_dir()?.join("instances"))
pub fn clusters_dir() -> crate::Result<PathBuf> {
Ok(app_config_dir()?.join("clusters"))
}
pub fn manifests_dir() -> crate::Result<PathBuf> {

View file

@ -6,9 +6,9 @@ fn main() {
InlinedPlugin::new().commands(&[
"login_msa",
"refresh_client_manager",
"create_instance",
"get_instances",
"get_instance",
"create_cluster",
"get_clusters",
"get_cluster",
"get_manifest",
]),
));

View file

@ -2,9 +2,9 @@
description = "Default permissions for the plugin"
permissions = [
"allow-refresh-client-manager",
"allow-create-instance",
"allow-get-instances",
"allow-get-instance",
"allow-create-cluster",
"allow-get-clusters",
"allow-get-cluster",
"allow-get-manifest",
"allow-login-msa",
]

View file

@ -1,4 +1,4 @@
use onelauncher::game::client::{ClientType, Instance, Manifest};
use onelauncher::game::client::{ClientType, Cluster, Manifest};
use tauri::State;
use tokio::sync::Mutex;
use uuid::Uuid;
@ -6,7 +6,7 @@ use uuid::Uuid;
use super::GameManagerState;
#[tauri::command]
pub async fn create_instance(
pub async fn create_cluster(
state: State<'_, Mutex<GameManagerState>>,
name: String,
version: String,
@ -16,26 +16,26 @@ pub async fn create_instance(
) -> Result<Uuid, String> {
let manager = &mut state.lock().await.client_manager;
let uuid = manager
.create_instance(name, version, cover, group, client)
.create_cluster(name, version, cover, group, client)
.await?;
Ok(uuid)
}
#[tauri::command]
pub async fn get_instances(
pub async fn get_clusters(
state: State<'_, Mutex<GameManagerState>>,
) -> Result<Vec<Instance>, String> {
) -> Result<Vec<Cluster>, String> {
let manager = &mut state.lock().await.client_manager;
Ok(manager.get_instances_owned())
Ok(manager.get_clusters_owned())
}
#[tauri::command]
pub async fn get_instance(
pub async fn get_cluster(
state: State<'_, Mutex<GameManagerState>>,
uuid: Uuid,
) -> Result<Instance, String> {
) -> Result<Cluster, String> {
let manager = &mut state.lock().await.client_manager;
let instance = manager.get_instance(uuid)?;
let instance = manager.get_cluster(uuid)?;
Ok(instance.clone())
}

View file

@ -23,9 +23,9 @@ pub fn init() -> TauriPlugin<tauri::Wry> {
})
.invoke_handler(tauri::generate_handler![
auth::login_msa,
game::create_instance,
game::get_instances,
game::get_instance,
game::create_cluster,
game::get_clusters,
game::get_cluster,
game::get_manifest,
refresh_client_manager,
])

View file

@ -1,7 +1,7 @@
import { invoke } from '@tauri-apps/api/core';
export async function getInstance(uuid: string): Promise<Core.Instance> {
return await invoke<Core.Instance>('plugin:onelauncher|get_instance', {
export async function getCluster(uuid: string): Promise<Core.Cluster> {
return await invoke<Core.Cluster>('plugin:onelauncher|get_cluster', {
uuid,
});
}
@ -12,22 +12,22 @@ export async function getManifest(uuid: string): Promise<Core.Manifest> {
});
}
export async function getInstancesWithManifests(): Promise<Core.InstanceWithManifest[]> {
const instances = await getInstances();
export async function getClustersWithManifests(): Promise<Core.ClusterWithManifest[]> {
const clusters = await getClusters();
return Promise.all(instances.map(async instance => ({
instance,
manifest: await getManifest(instance.id),
return Promise.all(clusters.map(async cluster => ({
cluster,
manifest: await getManifest(cluster.id),
})));
}
export async function getGroupedInstances(): Promise<Map<string, Core.InstanceWithManifest[]>> {
const instances = await getInstancesWithManifests();
const map = new Map<string, Core.InstanceWithManifest[]>();
export async function getClustersGrouped(): Promise<Map<string, Core.ClusterWithManifest[]>> {
const clusters = await getClustersWithManifests();
const map = new Map<string, Core.ClusterWithManifest[]>();
instances.forEach((instance, index) => {
const groupName = instance.instance.group || 'Unnamed';
const value = { ...instance, index };
clusters.forEach((cluster, index) => {
const groupName = cluster.cluster.group || 'Unnamed';
const value = { ...cluster, index };
if (map.has(groupName))
map.get(groupName)!.push(value);
@ -38,24 +38,19 @@ export async function getGroupedInstances(): Promise<Map<string, Core.InstanceWi
return map;
}
export async function getInstances(): Promise<Core.Instance[]> {
return await invoke<Core.Instance[]>('plugin:onelauncher|get_instances');
export async function getClusters(): Promise<Core.Cluster[]> {
return await invoke<Core.Cluster[]>('plugin:onelauncher|get_clusters');
}
export async function createInstance(instance: Omit<Core.Instance, 'id' | 'createdAt'> & { version: string }): Promise<void> {
export async function createCluster(cluster: Omit<Core.Cluster, 'id' | 'createdAt'> & { version: string }): Promise<void> {
return await invoke(
'plugin:onelauncher|create_instance',
'plugin:onelauncher|create_cluster',
{
name: instance.name,
version: instance.version,
client: instance.client,
// cover: instance.cover,
// group: instance.group,
},
{
headers: {
Accept: 'text/plain',
},
name: cluster.name,
version: cluster.version,
client: cluster.client,
// cover: cluster.cover,
// group: cluster.group,
},
);
}

View file

@ -8,18 +8,18 @@ import App from './ui/App';
import HomePage from './ui/pages/Home';
import BrowserPage from './ui/pages/Browser';
import UpdatesPage from './ui/pages/Updates';
import InstancePage from './ui/pages/instances';
import InstanceOverview from './ui/pages/instances/InstanceOverview';
import InstanceMods from './ui/pages/instances/InstanceMods';
import ClusterPage from './ui/pages/cluster';
import ClusterOverview from './ui/pages/cluster/ClusterOverview';
import ClusterMods from './ui/pages/cluster/ClusterMods';
render(() => (
<Router root={App}>
<Route path="/" component={HomePage} />
<Route path="/browser" component={BrowserPage} />
<Route path="/updates" component={UpdatesPage} />
<Route path="/instances" component={InstancePage}>
<Route path="/" component={InstanceOverview} />
<Route path="/mods" component={InstanceMods} />
<Route path="/clusters" component={ClusterPage}>
<Route path="/" component={ClusterOverview} />
<Route path="/mods" component={ClusterMods} />
</Route>
</Router>
), document.getElementById('root') as HTMLElement);

6
src/types/game.d.ts vendored
View file

@ -1,6 +1,6 @@
declare namespace Core {
export interface InstanceWithManifest {
instance: Instance,
export interface ClusterWithManifest {
cluster: Cluster,
manifest: Manifest,
}
@ -16,7 +16,7 @@ declare namespace Core {
},
}
export interface Instance<T extends keyof ClientType = keyof ClientType> {
export interface Cluster<T extends keyof ClientType = keyof ClientType> {
id: string,
createdAt: number,
name: string,

View file

@ -1,7 +1,6 @@
import {
CheckIcon,
DotsVerticalIcon,
Download01Icon,
EyeIcon,
PlayIcon,
PlusIcon,
@ -16,8 +15,7 @@ import Tag from '../components/base/Tag';
import TextField from '../components/base/TextField';
import defaultCover from '../../assets/images/default_instance_cover.jpg';
import ContextMenu from '../components/overlay/ContextMenu';
import { createInstance, getGroupedInstances, getInstancesWithManifests } from '../../bridge/game';
import Modal from '../components/overlay/Modal';
import { createCluster, getClustersGrouped } from '../../bridge/game';
// TODO: Replace this into it's own component
// possibly with the core ui lirbary with autogenerated and optimized svgs pls
@ -63,14 +61,14 @@ function Banner() {
);
}
interface InstanceCardContextMenuProps {
interface ClusterCardContextMenuProps {
pos: Accessor<{ x: number; y: number }>;
contextMenuVisible: Accessor<boolean>;
setContextMenuVisible: Setter<boolean>;
id: string;
}
function InstanceCardContextMenu(props: InstanceCardContextMenuProps) {
function ClusterCardContextMenu(props: ClusterCardContextMenuProps) {
const navigate = useNavigate();
return (
@ -83,7 +81,7 @@ function InstanceCardContextMenu(props: InstanceCardContextMenuProps) {
icon={<EyeIcon />}
text="View"
onClick={() => {
navigate(`/instances/?id=${props.id}`);
navigate(`/clusters/?id=${props.id}`);
}}
/>
@ -106,14 +104,14 @@ declare module 'solid-js' {
}
}
function InstanceCard(props: Core.InstanceWithManifest) {
function ClusterCard(props: Core.ClusterWithManifest) {
const navigate = useNavigate();
const [pos, setPos] = createSignal({ x: 0, y: 0 });
const [contextMenuVisible, setContextMenuVisible] = createSignal(false);
let ref!: HTMLDivElement;
function openInstancePage(_e: MouseEvent) {
navigate(`/instances/?id=${props.instance.id}`);
function openClusterPage(_e: MouseEvent) {
navigate(`/clusters/?id=${props.cluster.id}`);
}
function openContextMenu(e: MouseEvent) {
@ -129,7 +127,7 @@ function InstanceCard(props: Core.InstanceWithManifest) {
return (
<>
<div
onClick={e => openInstancePage(e)}
onClick={e => openClusterPage(e)}
onMouseDown={e => onMouseDown(e)}
onContextMenu={e => openContextMenu(e)}
ref={ref}
@ -141,16 +139,16 @@ function InstanceCard(props: Core.InstanceWithManifest) {
style={{ '-webkit-transform': 'translateZ(0)' }}
>
<img
class={`object-cover h-full w-full ${props.instance.cover ? '' : ' filter grayscale'}`}
src={props.instance.cover || defaultCover}
class={`object-cover h-full w-full ${props.cluster.cover ? '' : ' filter grayscale'}`}
src={props.cluster.cover || defaultCover}
/>
</div>
</div>
<div class="z-10 p-3 flex flex-row items-center justify-between">
<div class="flex flex-col gap-1.5">
<p class="h-4 font-semibold">{props.instance.name}</p>
<p class="h-4 font-semibold">{props.cluster.name}</p>
<p class="h-4 text-xs">
{props.instance.client.type}
{props.cluster.client.type}
{' '}
{props.manifest.manifest.id}
{/* {' '}
@ -162,38 +160,38 @@ function InstanceCard(props: Core.InstanceWithManifest) {
</Button>
</div>
</div>
<InstanceCardContextMenu
<ClusterCardContextMenu
contextMenuVisible={contextMenuVisible}
setContextMenuVisible={setContextMenuVisible}
pos={pos}
id={props.instance.id}
id={props.cluster.id}
/>
</>
);
}
interface InstanceGroupProps {
interface ClusterGroupProps {
title: string;
instances: Core.InstanceWithManifest[];
clusters: Core.ClusterWithManifest[];
}
function InstanceGroup(props: InstanceGroupProps) {
function ClusterGroup(props: ClusterGroupProps) {
return (
<div class="flex flex-col gap-y-4">
<h4>{props.title}</h4>
<div class="grid grid-cols-4 2xl:grid-cols-6 gap-4">
<For each={props.instances}>{item => <InstanceCard {...item} />}</For>
<For each={props.clusters}>{item => <ClusterCard {...item} />}</For>
</div>
</div>
);
}
function HomePage() {
const [instances, { refetch }] = createResource(getGroupedInstances);
const [clusters, { refetch }] = createResource(getClustersGrouped);
async function newInstance() {
await createInstance({
name: 'New Instance',
await createCluster({
name: 'New Cluster',
version: '1.8.9',
client: {
type: 'Vanilla',
@ -217,22 +215,22 @@ function HomePage() {
<Button
styleType="primary"
iconLeft={<PlusIcon class="!w-5 stroke-[2.2]" />}
children="New Instance"
children="New Cluster"
onClick={() => newInstance()}
/>
<Button
{/* <Button
styleType="secondary"
iconLeft={<Download01Icon />}
children="From URL"
/>
/> */}
</div>
</div>
<Show when={instances() !== undefined}>
<For each={Array.from(instances()!.entries())}>
{([title, instances]) => (
<InstanceGroup title={title} instances={instances} />
<Show when={clusters() !== undefined}>
<For each={Array.from(clusters()!.entries())}>
{([title, clusters]) => (
<ClusterGroup title={title} clusters={clusters} />
)}
</For>
</Show>

View file

@ -1,4 +1,4 @@
function InstanceMods() {
function ClusterMods() {
return (
<div>
<h1>This is the Mods page</h1>
@ -6,4 +6,4 @@ function InstanceMods() {
);
}
export default InstanceMods;
export default ClusterMods;

View file

@ -1,4 +1,4 @@
function InstanceOverview() {
function ClusterOverview() {
return (
<div>
<h1>This is the overview</h1>
@ -6,4 +6,4 @@ function InstanceOverview() {
);
}
export default InstanceOverview;
export default ClusterOverview;

View file

@ -10,7 +10,7 @@ function Link(props: AnchorProps) {
);
}
function InstancePage(props: ParentProps) {
function ClusterPage(props: ParentProps) {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
@ -22,8 +22,8 @@ function InstancePage(props: ParentProps) {
return (
<div>
<div>
<Link href="/instances/">Overview</Link>
<Link href="/instances/mods">mods</Link>
<Link href="/clusters/">Overview</Link>
<Link href="/clusters/mods">mods</Link>
</div>
{props.children}
{searchParams.id}
@ -31,4 +31,4 @@ function InstancePage(props: ParentProps) {
);
}
export default InstancePage;
export default ClusterPage;