From a364d4330dfd34f953f64e90020f8b8d6f2e82c4 Mon Sep 17 00:00:00 2001 From: Physcik Date: Sat, 10 Jan 2026 17:27:55 +0500 Subject: World storage system change --- engine/Dynamic/Common.go | 23 +++++++ engine/Dynamic/Descriptors/Assets.go | 5 ++ engine/Dynamic/Descriptors/Tile.go | 24 +++++++ engine/Dynamic/Descriptors/World.go | 28 +++++++++ engine/Dynamic/Manager.go | 51 +++++++++++++++ engine/Dynamic/Package.go | 118 +++++++++++++++++++++++++++++++++++ engine/Dynamic/Validation.go | 15 +++++ 7 files changed, 264 insertions(+) create mode 100644 engine/Dynamic/Common.go create mode 100644 engine/Dynamic/Descriptors/Assets.go create mode 100644 engine/Dynamic/Descriptors/Tile.go create mode 100644 engine/Dynamic/Descriptors/World.go create mode 100644 engine/Dynamic/Manager.go create mode 100644 engine/Dynamic/Package.go create mode 100644 engine/Dynamic/Validation.go (limited to 'engine/Dynamic') diff --git a/engine/Dynamic/Common.go b/engine/Dynamic/Common.go new file mode 100644 index 0000000..99cfdc2 --- /dev/null +++ b/engine/Dynamic/Common.go @@ -0,0 +1,23 @@ +package dynamic + +import ( + "encoding/json" + "fmt" + "os" +) + +func ReadJSONfromFile(fileLocation string, v any) error { + var file, openErr = os.ReadFile(fileLocation) + if openErr != nil { + return openErr + } + var jsonErr = json.Unmarshal(file, v) + if jsonErr != nil { + return jsonErr + } + return nil +} + +func ConcantinateFileLocation(baseDirLocation string, appendix string) string { + return fmt.Sprintf("%v/%v", baseDirLocation, appendix) +} diff --git a/engine/Dynamic/Descriptors/Assets.go b/engine/Dynamic/Descriptors/Assets.go new file mode 100644 index 0000000..864761d --- /dev/null +++ b/engine/Dynamic/Descriptors/Assets.go @@ -0,0 +1,5 @@ +package descriptors + +type AssetsDescriptor struct { + Textures map[int]string `json:"textures"` +} diff --git a/engine/Dynamic/Descriptors/Tile.go b/engine/Dynamic/Descriptors/Tile.go new file mode 100644 index 0000000..09c8c62 --- /dev/null +++ b/engine/Dynamic/Descriptors/Tile.go @@ -0,0 +1,24 @@ +package descriptors + +import rl "github.com/gen2brain/raylib-go/raylib" + +// Represents a type of a tile that can be used in the world +type TileDescriptor struct { + Id uint64 `json:"id"` + Position rl.Vector2 `json:"position"` + TextureId int `json:"textureid"` + OveralyTextureId int `json:"overalytextureid"` +} + +func (base *TileDescriptor) IsValid() error { + return nil +} + +// Maps the tiles by IDs +func MapTileDescriptors(data []*TileDescriptor) map[uint64]*TileDescriptor { + var outp = make(map[uint64]*TileDescriptor) + for _, v := range data { + outp[v.Id] = v + } + return outp +} diff --git a/engine/Dynamic/Descriptors/World.go b/engine/Dynamic/Descriptors/World.go new file mode 100644 index 0000000..00e17f3 --- /dev/null +++ b/engine/Dynamic/Descriptors/World.go @@ -0,0 +1,28 @@ +package descriptors + +import rl "github.com/gen2brain/raylib-go/raylib" + +type WorldDescriptor struct { + Name string + // Deprecated + TileSize rl.Vector2 `json:"-"` + FloorMap []FloorPiece +} + +func (base *WorldDescriptor) IsValid() error { + return nil +} + +// Maps the world descriptor by IDs +func MapWorldDescriptors(data []*WorldDescriptor) map[string]*WorldDescriptor { + var outp = make(map[string]*WorldDescriptor) + for _, v := range data { + outp[v.Name] = v + } + return outp +} + +type FloorPiece struct { + Position rl.Vector2 + TextureId uint64 +} diff --git a/engine/Dynamic/Manager.go b/engine/Dynamic/Manager.go new file mode 100644 index 0000000..7e5a567 --- /dev/null +++ b/engine/Dynamic/Manager.go @@ -0,0 +1,51 @@ +package dynamic + +import ( + "fmt" + "os" + + settings "github.com/DegustatorPonos/RuinesOfRafdolon/Settings" + rl "github.com/gen2brain/raylib-go/raylib" +) + +// The collection of all avaliable packages that are loaded in the system +type PackageManager struct { + AvaliablePackages map[string]Package +} + +var Manager *PackageManager = nil + +func loadPackages() (*PackageManager, error) { + var dir, dirErr = os.ReadDir(settings.Current.PackagesLocation) + if dirErr != nil { + return nil, dirErr + } + var outp = PackageManager{ + AvaliablePackages: make(map[string]Package), + } + for _, v := range dir { + var packagePath = ConcantinateFileLocation(settings.Current.PackagesLocation, v.Name()) + var newPackage, packageErr = ReadPackage(v) + if packageErr != nil { + rl.TraceLog(rl.LogWarning, "Failed to load the module %v: %s", packagePath, packageErr.Error()) + continue + } + newPackage.location = packagePath + + // newPackage.LoadTiles() + newPackage.LoadWorlds() + + outp.AvaliablePackages[newPackage.Description.Name] = *newPackage + rl.TraceLog(rl.LogInfo, "Loaded the module %s", newPackage.Description.Name) + } + return &outp, nil +} + +// Loads the packages from the specified in settings directory. Panics on serious error +func Init() { + var manager, err = loadPackages() + if err != nil { + panic(fmt.Sprintf("Failed to load packages: %v", err.Error())) + } + Manager = manager +} diff --git a/engine/Dynamic/Package.go b/engine/Dynamic/Package.go new file mode 100644 index 0000000..8cabc91 --- /dev/null +++ b/engine/Dynamic/Package.go @@ -0,0 +1,118 @@ +package dynamic + +import ( + "encoding/json" + "fmt" + "os" + + descriptors "github.com/DegustatorPonos/RuinesOfRafdolon/Dynamic/Descriptors" + settings "github.com/DegustatorPonos/RuinesOfRafdolon/Settings" + rl "github.com/gen2brain/raylib-go/raylib" +) + +// The defenition of the package +type PackageDescription struct { + Name string `json:"name"` + Version uint64 `json:"version"` + Type string `json:"type"` + MinimumVersion *settings.AppVersion + MaximumVersion *settings.AppVersion +} + +func (base *PackageDescription) IsValid() error { + if base.Name == "" { + return fmt.Errorf("Invalid package descriptor: the name cannot be empty") + } + if base.Version == 0 { + return fmt.Errorf("Invalid package descriptor: the version cannot be 0") + } + if base.MinimumVersion == nil { + return fmt.Errorf("Invalid package descriptor: The package must specify the minimal version") + } + if !base.MinimumVersion.IsCompatible() || (base.MaximumVersion != nil && !base.MaximumVersion.IsLessThan(&settings.Current.Version)){ + return fmt.Errorf("Invalid package descriptor: The package is made for the newer or older version") + } + return nil +} + +// The dynamic collection of the things +type Package struct { + Description PackageDescription + Worlds map[string]*descriptors.WorldDescriptor + + location string +} + +func (base *Package) String() string { + var outp, jsonErr = json.Marshal(base) + if jsonErr != nil { + return fmt.Sprintf("Failed to parse settings: %s", jsonErr.Error()) + } + return string(outp) +} + +func ReadPackage(dir os.DirEntry) (*Package, error) { + var dirPath = ConcantinateFileLocation(settings.Current.PackagesLocation, dir.Name()) + var desc = PackageDescription{} + if descErr := ReadValidJSONfromFile(ConcantinateFileLocation(dirPath, "Description.json"), &desc); descErr != nil { + return nil, descErr + } + return &Package{ + Description: desc, + }, nil +} + +func loadAssetsFromDir[T Validatable](dirLocation string, InitializeFunc func()T) ([]T, error) { + var files, err = os.ReadDir(dirLocation) + if err != nil { + return nil, err + } + var outp = make([]T, 0) + for _, v := range files { + var new = InitializeFunc() + var loadErr = ReadValidJSONfromFile(ConcantinateFileLocation(dirLocation, v.Name()), new) + if loadErr != nil { + rl.TraceLog(rl.LogWarning, "Failed to load the asset %s: %s", v.Name(), loadErr) + continue + } + outp = append(outp, new) + } + return outp, nil +} + +func (base *Package) LoadWorlds() { + if base.Description.Type != "story" { + return + } + var worlds, loadErr = loadWorldsFromDir(ConcantinateFileLocation(base.location, "Worlds")) + if loadErr != nil { + rl.TraceLog(rl.LogWarning, "Failed to load world from the module %s: %s", base.location, loadErr) + } else { + base.Worlds = worlds + } +} + +// func (base *Package) LoadTiles() { + // var tiles, loadErr = loadTilesFromDir(ConcantinateFileLocation(base.location, "Worlds")) + // if loadErr != nil { + // rl.TraceLog(rl.LogWarning, "Failed to load tiles from the module %s: %s", base.location, loadErr) + // } else { + // base.Tiles = tiles + // } +// } + +func loadWorldsFromDir(dirLocation string) (map[string]*descriptors.WorldDescriptor, error) { + var loaded, err = loadAssetsFromDir(dirLocation, func() *descriptors.WorldDescriptor{ return &descriptors.WorldDescriptor{} }) + if err != nil { + return nil, err + } + return descriptors.MapWorldDescriptors(loaded), nil +} + +func loadTilesFromDir(dirLocation string) (map[uint64]*descriptors.TileDescriptor, error) { + var loaded, err = loadAssetsFromDir(dirLocation, func() *descriptors.TileDescriptor{ return &descriptors.TileDescriptor{} }) + if err != nil { + return nil, err + } + return descriptors.MapTileDescriptors(loaded), nil +} diff --git a/engine/Dynamic/Validation.go b/engine/Dynamic/Validation.go new file mode 100644 index 0000000..dfe1d5c --- /dev/null +++ b/engine/Dynamic/Validation.go @@ -0,0 +1,15 @@ +package dynamic + +type Validatable interface { + // If the object is returned invalid this function should return the reason + IsValid() error +} + +// Reads object fron the file and validates it +func ReadValidJSONfromFile(fileLocation string, v Validatable) error { + var err = ReadJSONfromFile(fileLocation, v) + if err != nil { + return err + } + return v.IsValid() +} -- cgit v1.3