Skip to content

Commit

Permalink
primitive profile manager
Browse files Browse the repository at this point in the history
  • Loading branch information
Owen3H committed Nov 20, 2024
1 parent f0837e5 commit 046025b
Show file tree
Hide file tree
Showing 26 changed files with 563 additions and 366 deletions.
4 changes: 0 additions & 4 deletions backend/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ func (u *Utils) WalkDirExt(root string, exts []string) ([]string, error) {
return backend.WalkDirExt(root, exts)
}

func (u *Utils) ReadFile(path string) (*string, error) {
return backend.ReadFile(path)
}

func (app *Application) GetSettings() *AppSettings {
return app.Settings
}
Expand Down
113 changes: 111 additions & 2 deletions backend/common/profile/manager.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,113 @@
package profile

type ModStore map[string]IMod
type ProfileStore = map[string]Profile
import (
"encoding/json"
"modm8/backend"
"os"
"path/filepath"
"strings"
)

// type ModStore map[string]IMod
// type ProfileStore = map[string]Profile

type ProfileManager struct{}

func NewManager() *ProfileManager {
return &ProfileManager{}
}

type ProfileMods struct {
Thunderstore []string `json:"thunderstore"`
Nexus []string `json:"nexus"`
}

type ProfileManifest struct {
Mods ProfileMods `json:"mods"`
}

func (pm *ProfileManager) GetProfiles(gameTitle string) (map[string]ProfileManifest, error) {
return GetProfiles(gameTitle)
}

func (pm *ProfileManager) GetProfile(gameTitle, profileName string) (*ProfileManifest, error) {
return GetManifest(gameTitle, profileName)
}

func (pm *ProfileManager) SaveProfile(gameTitle, profileName string, prof ProfileManifest) error {
return SaveManifest(gameTitle, profileName, prof)
}

func PathToProfilesDir(gameTitle string) string {
cacheDir, _ := os.UserConfigDir()
path := filepath.Join(cacheDir, "modm8", "Games", gameTitle, "Profiles")

return path
}

func PathToProfile(gameTitle, profileName string) string {
return filepath.Join(PathToProfilesDir(gameTitle), profileName+".prof")
}

func GetProfileNames(gameTitle string) ([]string, error) {
profDir := PathToProfilesDir(gameTitle)

// The user probably hasn't created a profiles yet.
exists, _ := backend.ExistsAtPath(profDir)
if !exists {
return []string{}, nil
}

paths, err := backend.WalkDirExt(profDir, []string{"prof"})
if err != nil {
return []string{}, err
}

var names []string
for _, path := range paths {
name := strings.Replace(filepath.Base(path), ".prof", "", -1)
names = append(names, name)
}

return names, nil
}

func SaveManifest(gameTitle, profileName string, prof ProfileManifest) error {
data, err := json.Marshal(prof)
if err != nil {
return err
}

return backend.SaveFile(PathToProfile(gameTitle, profileName), data)
}

func GetManifest(gameTitle, profileName string) (*ProfileManifest, error) {
contents, err := backend.ReadFile(PathToProfile(gameTitle, profileName))
if err != nil {
return nil, err
}

var manifest ProfileManifest
if err := json.Unmarshal(contents, &manifest); err != nil {
return nil, err
}

return &manifest, nil
}

func GetProfiles(gameTitle string) (map[string]ProfileManifest, error) {
profNames, err := GetProfileNames(gameTitle)
if err != nil {
return nil, err
}

profiles := make(map[string]ProfileManifest)
for _, name := range profNames {
manifest, _ := GetManifest(gameTitle, name)
if manifest != nil {
profiles[name] = *manifest
}
}

return profiles, err
}
40 changes: 22 additions & 18 deletions backend/common/profile/profile.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
package profile

type Profile struct {
Name string `json:"name" mapstructure:"name"`
Favourited bool `json:"favourited" mapstructure:"favourited"`
Mods ModStore `json:"mods" mapstructure:"mods"`
}
// type Profile struct {
// Name string `json:"name" mapstructure:"name"`
// //Favourited bool `json:"favourited" mapstructure:"favourited"`
// Mods ModStore `json:"mods" mapstructure:"mods"`
// }

func NewProfile(name string) Profile {
return Profile{
Name: name,
Favourited: false,
Mods: ModStore{},
}
}
// func NewProfile(name string) Profile {
// return Profile{
// Name: name,
// //Favourited: false,
// Mods: ModStore{},
// }
// }

func (p *Profile) Favourite() {
p.Favourited = true
}
// func (p *Profile) AddMod(name string, mod IMod) {
// p.Mods[name] = mod
// }

func (p *Profile) AddMod(name string, mod IMod) {
p.Mods[name] = mod
}
// func (p *Profile) Rename(name string) {
// p.Name = name
// }

// // func (p *Profile) Favourite() {
// // p.Favourited = true
// // }
3 changes: 2 additions & 1 deletion backend/game/bepinex.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ func ParseBepinexConfig(path string) (*BepinexConfig, error) {
acceptableValues = make([]string, 0)
}

lines := strings.Split(*contents, "\n")
lines := strings.Split(string(contents), "\n")

for _, line := range lines {
line = strings.TrimSpace(line)

Expand Down
2 changes: 1 addition & 1 deletion backend/game/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type LoaderPackageInfo struct {
RootDirName *string
}

// Note: Since Go can't do overloading, recommended version is kwargs - but only the first element will matter.
// Note: Since Go can't do overloading, recommendedVer is kwargs - but only the first element will matter.
func NewLoaderPackageInfo(loaderType ModLoader, rootDirName string, recommendedVer ...*semver.Version) LoaderPackageInfo {
var version *semver.Version
if len(recommendedVer) > 0 {
Expand Down
27 changes: 27 additions & 0 deletions backend/tests/profile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package backend

import (
"modm8/backend/common/profile"
"testing"
)

func TestWriteProfile(t *testing.T) {
manifest := profile.ProfileManifest{
Mods: profile.ProfileMods{
Thunderstore: []string{"example-ts-mod-4.2.0"},
Nexus: []string{"example-nexus-mod-6.9.0"},
},
}

err := profile.SaveManifest("Lethal Company", "test", manifest)
if err != nil {
t.Fatal(err)
}
}

func TestReadProfile(t *testing.T) {
_, err := profile.GetManifest("Lethal Company", "test")
if err != nil {
t.Fatal(err)
}
}
2 changes: 1 addition & 1 deletion backend/thunderstore/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ var CurModCacheDir string

func ModCacheDir(gameTitle string) string {
cacheDir, _ := os.UserConfigDir()
return filepath.Join(cacheDir, "modm8", "Thunderstore", gameTitle, "ModCache")
return filepath.Join(cacheDir, "modm8", "Games", gameTitle, "ModCache")
}

type StrippedPackage struct {
Expand Down
17 changes: 7 additions & 10 deletions backend/util.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package backend

import (
"io/fs"
"os"
"path/filepath"
"strings"
)

func WalkDirExt(root string, exts []string) ([]string, error) {
var files []string
err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
if !d.IsDir() {
err := filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error {
if !entry.IsDir() {
for _, s := range exts {
if strings.HasSuffix(path, "."+s) {
files = append(files, path)
Expand Down Expand Up @@ -40,14 +39,12 @@ func ExistsAtPath(absPath string) (bool, error) {
return err == nil, err
}

func ReadFile(path string) (*string, error) {
content, err := os.ReadFile(filepath.Clean(path))
if err != nil {
return nil, nil
}
func ReadFile(path string) ([]byte, error) {
return os.ReadFile(filepath.Clean(path))
}

out := string(content)
return &out, nil
func SaveFile(path string, data []byte) error {
return os.WriteFile(filepath.Clean(path), data, os.ModePerm)
}

func ContainsEqualFold(arr []string, item string) bool {
Expand Down
21 changes: 10 additions & 11 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,19 @@ const { setMaxThreads } = useAppStore()
const onKeydown = (event: KeyboardEvent) => {
console.log('Keydown fired!\n', event.key)
const openDialogs = getOpenDialogs()
if (openDialogs.length > 0) {
for (const dialog of openDialogs) {
dialog.visible.value = false
if (event.key == "Escape") {
const openDialogs = getOpenDialogs()
if (openDialogs.length > 0) {
for (const dialog of openDialogs) {
dialog.visible.value = false
}
return
}
return
// No dialogs open + ESC -> open settings overlay.
// settingsDialog.setVisible(!settingsDialog.visible.value)
}
// No dialogs open + pressing ESC -> open settings overlay.
// if (event.key == 'Escape') {
// settingsDialog.setVisible(!settingsDialog.visible.value)
// }
}
onMounted(async () => {
Expand All @@ -45,7 +45,6 @@ onMounted(async () => {
// We don't use `navigator.hardwareConcurrency` as it is known to be unreliable.
setMaxThreads(await NumCPU())
// Add keydown event listener when the app mounts
window.addEventListener('keydown', onKeydown)
})
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/assets/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,19 @@
}

html {
width: 100vw;
height: 100vh;
width: 100%;
height: 100%;
overflow: hidden;
}

body {
width: 100vw;
height: 100vh;
position: relative;
box-sizing: border-box;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}

body::before {
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/reusable/PlatformSelectPanels.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Splitter from 'primevue/splitter'
import SplitterPanel from 'primevue/splitterpanel'
//import OutlineHoverButton from "./OutlineHoverButton.vue"
const props = defineEmits(['selectThunderstore', 'selectNexus'])
const emit = defineEmits(['selectThunderstore', 'selectNexus'])
</script>

<template>
Expand All @@ -17,7 +17,7 @@ const props = defineEmits(['selectThunderstore', 'selectNexus'])
<div class="blur w-full h-full">
<div class="flex column panel-text">
Thunderstore
<Button class="mt-3" label="Select" @click="$emit('selectThunderstore')"/>
<Button class="mt-3" label="Select" @click="emit('selectThunderstore')"/>
</div>
</div>
</SplitterPanel>
Expand All @@ -26,7 +26,7 @@ const props = defineEmits(['selectThunderstore', 'selectNexus'])
<div class="blur w-full h-full">
<div class="flex column panel-text">
Nexus Mods
<Button class="mt-3" label="Select" @click="$emit('selectNexus')"/>
<Button class="mt-3" label="Select" @click="emit('selectNexus')"/>
</div>
</div>
</SplitterPanel>
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/reusable/Viewport.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const appStore = useAppStore()
const {
sidebarWidth
} = storeToRefs(appStore)
const topbarHeight = '30px'
</script>

<template>
Expand All @@ -16,6 +18,7 @@ const {

<style scoped>
.viewport {
max-height: calc(100vh - v-bind(topbarHeight));
margin-left: calc(v-bind(sidebarWidth) + 20px);
margin-right: 20px;
}
Expand Down
Loading

0 comments on commit 046025b

Please sign in to comment.