Adding modding folder with a hacked build.
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
package world
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/inkyblackness/hacked/ss1/content/object"
|
||||
"github.com/inkyblackness/hacked/ss1/content/texture"
|
||||
"github.com/inkyblackness/hacked/ss1/resource"
|
||||
"github.com/inkyblackness/hacked/ss1/serial/rle"
|
||||
"github.com/inkyblackness/hacked/ss1/world/ids"
|
||||
)
|
||||
|
||||
// LocalizedResources associates a language with a resource store under a specific filename.
|
||||
type LocalizedResources struct {
|
||||
// File describes from which file the data was possibly loaded from, and where it should be stored in.
|
||||
File FileLocation
|
||||
// Template specifies the "original" filename the data would be stored in.
|
||||
// For example, savegames have "archive.dat" as their template.
|
||||
// Note: This could be expanded to be a list. The loader could check which IDs are all stored in the loaded file,
|
||||
// and match all corresponding templates. Though, this works only for "Any" language resources.
|
||||
Template string
|
||||
// Language identifies the language this package of resources is for.
|
||||
Language resource.Language
|
||||
// Store contains all the resources.
|
||||
Store resource.Store
|
||||
}
|
||||
|
||||
// ModData contains the core information about a mod.
|
||||
type ModData struct {
|
||||
FileChangeCallback func(string)
|
||||
|
||||
LocalizedResources []*LocalizedResources
|
||||
ObjectProperties object.PropertiesTable
|
||||
TextureProperties texture.PropertiesList
|
||||
}
|
||||
|
||||
// SetResourceBlock changes the block data of a resource.
|
||||
//
|
||||
// If the block data is not empty, then:
|
||||
// If the resource does not exist, it will be created with default meta information.
|
||||
// If the block does not exist, the resource is extended to allow its addition.
|
||||
//
|
||||
// If the block data is empty (or nil), then the block is cleared.
|
||||
func (data *ModData) SetResourceBlock(lang resource.Language, id resource.ID, index int, blockData []byte) {
|
||||
loc, res := data.ensureResource(lang, id)
|
||||
res.SetBlock(index, blockData)
|
||||
data.notifyFileChanged(loc.File.Name)
|
||||
}
|
||||
|
||||
// PatchResourceBlock modifies an existing block.
|
||||
// This modification assumes the block already exists and can take the given patch data.
|
||||
// The patch data is expected to be produced by rle.Compress().
|
||||
func (data *ModData) PatchResourceBlock(lang resource.Language, id resource.ID, index int, expectedLength int, patch []byte) {
|
||||
loc, res := data.ensureResource(lang, id)
|
||||
raw, err := res.BlockRaw(index)
|
||||
if (err == nil) && (len(raw) == expectedLength) {
|
||||
_ = rle.Decompress(bytes.NewReader(patch), raw)
|
||||
data.notifyFileChanged(loc.File.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// SetResourceBlocks sets the entire list of block data of a resource.
|
||||
// This method is primarily meant for compound non-list resources (e.g. text pages).
|
||||
func (data *ModData) SetResourceBlocks(lang resource.Language, id resource.ID, blocks [][]byte) {
|
||||
loc, res := data.ensureResource(lang, id)
|
||||
res.Set(blocks)
|
||||
data.notifyFileChanged(loc.File.Name)
|
||||
}
|
||||
|
||||
// DelResource removes a resource from the mod in the given language.
|
||||
func (data *ModData) DelResource(lang resource.Language, id resource.ID) {
|
||||
for _, loc := range data.LocalizedResources {
|
||||
if (loc.Language == lang) && loc.Store.Del(id) {
|
||||
data.notifyFileChanged(loc.File.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SetTextureProperties updates the properties of a specific texture.
|
||||
func (data *ModData) SetTextureProperties(index int, properties texture.Properties) {
|
||||
if (index >= 0) && (index < len(data.TextureProperties)) {
|
||||
data.TextureProperties[index] = properties
|
||||
data.notifyFileChanged(TexturePropertiesFilename)
|
||||
}
|
||||
}
|
||||
|
||||
// SetObjectProperties updates the properties of a specific object.
|
||||
func (data *ModData) SetObjectProperties(triple object.Triple, properties object.Properties) {
|
||||
entry, err := data.ObjectProperties.ForObject(triple)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
*entry = properties.Clone()
|
||||
data.notifyFileChanged(ObjectPropertiesFilename)
|
||||
}
|
||||
|
||||
func (data *ModData) ensureResource(lang resource.Language, id resource.ID) (*LocalizedResources, *resource.Resource) {
|
||||
for _, loc := range data.LocalizedResources {
|
||||
if loc.Language == lang {
|
||||
res, err := loc.Store.Resource(id)
|
||||
if err == nil {
|
||||
return loc, res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data.newResource(lang, id)
|
||||
}
|
||||
|
||||
func (data *ModData) newResource(lang resource.Language, id resource.ID) (*LocalizedResources, *resource.Resource) {
|
||||
compound := true
|
||||
contentType := resource.ContentType(0xFF) // Default to something completely unknown.
|
||||
compressed := false
|
||||
filename := "unknown.res"
|
||||
|
||||
if info, known := ids.Info(id); known {
|
||||
compound = info.Compound
|
||||
contentType = info.ContentType
|
||||
compressed = info.Compressed
|
||||
filename = info.ResFile.For(lang)
|
||||
}
|
||||
|
||||
loc := data.ensureStore(lang, filename)
|
||||
_ = loc.Store.Put(id, resource.Resource{
|
||||
Properties: resource.Properties{
|
||||
Compound: compound,
|
||||
ContentType: contentType,
|
||||
Compressed: compressed,
|
||||
},
|
||||
})
|
||||
res, _ := loc.Store.Resource(id)
|
||||
return loc, res
|
||||
}
|
||||
|
||||
func (data *ModData) ensureStore(lang resource.Language, filename string) *LocalizedResources {
|
||||
for _, loc := range data.LocalizedResources {
|
||||
if (loc.Language == lang) && (loc.Template == filename) {
|
||||
return loc
|
||||
}
|
||||
}
|
||||
loc := &LocalizedResources{
|
||||
File: FileLocation{DirPath: ".", Name: filename},
|
||||
Template: filename,
|
||||
Language: lang,
|
||||
}
|
||||
data.LocalizedResources = append(data.LocalizedResources, loc)
|
||||
return loc
|
||||
}
|
||||
|
||||
func (data ModData) notifyFileChanged(filename string) {
|
||||
if data.FileChangeCallback != nil {
|
||||
data.FileChangeCallback(filename)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user