Adding modding folder with a hacked build.

This commit is contained in:
ml
2026-09-26 08:53:08 +02:00
parent cdb960dc71
commit c91080aba7
755 changed files with 50424 additions and 0 deletions
+154
View File
@@ -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)
}
}