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
+208
View File
@@ -0,0 +1,208 @@
package world
import (
"archive/zip"
"bytes"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"github.com/inkyblackness/hacked/ss1/content/archive"
"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/resource/lgres"
"github.com/inkyblackness/hacked/ss1/serial"
"github.com/inkyblackness/hacked/ss1/world/ids"
)
var fileAllowlist = ids.FilenameList{
ids.Archive,
ids.CybStrng,
ids.CitALog,
ids.CitBark,
ids.CitMat,
ids.DigiFX,
ids.GamePal,
ids.GameScr,
ids.MfdArt,
ids.Obj3D,
ids.ObjArt,
ids.ObjArt2,
ids.ObjArt3,
ids.SideArt,
ids.Splash,
ids.SvgaDeth,
ids.SvgaEnd,
ids.SvgaIntr,
ids.Texture,
ids.VidMail,
}
type fileLoader struct {
resultMutex sync.Mutex
allowZips bool
result FileLoadResult
}
// FileLoadResult contains all the information of a LoadFiles attempt.
type FileLoadResult struct {
FailedFiles int
Savegames map[FileLocation]resource.Viewer
Resources map[FileLocation]resource.Viewer
ObjectProperties object.PropertiesTable
TextureProperties texture.PropertiesList
}
// LoadFiles attempts to load compatible files from the given set of filenames.
func LoadFiles(allowZips bool, names []string) FileLoadResult {
loader := fileLoader{
allowZips: allowZips,
result: FileLoadResult{
Resources: make(map[FileLocation]resource.Viewer),
Savegames: make(map[FileLocation]resource.Viewer),
},
}
loader.loadAll(names)
return loader.result
}
func (loader *fileLoader) loadAll(names []string) {
loader.loadList(names, len(names) == 1)
}
func (loader *fileLoader) loadList(names []string, isOnlyRequestedFile bool) {
var wg sync.WaitGroup
for _, name := range names {
wg.Add(1)
go func(name string) {
defer wg.Done()
loader.load(name, isOnlyRequestedFile)
}(name)
}
wg.Wait()
}
func (loader *fileLoader) load(name string, isOnlyRequestedFile bool) {
fileInfo, err := os.Stat(name)
if err != nil {
loader.markFailedFile()
return
}
file, err := os.Open(name)
if err != nil {
loader.markFailedFile()
return
}
defer func() {
_ = file.Close() // nolint: gas
}()
if fileInfo.IsDir() {
if isOnlyRequestedFile {
subNames, _ := file.Readdirnames(0)
joinedSubNames := make([]string, len(subNames))
for index, subName := range subNames {
joinedSubNames[index] = filepath.Join(name, subName)
}
loader.loadList(joinedSubNames, false)
}
} else {
tryDirect := true
if loader.allowZips && isOnlyRequestedFile {
tryDirect = false
zipReader, err := zip.NewReader(file, fileInfo.Size())
if err != nil {
_, _ = file.Seek(0, io.SeekStart)
tryDirect = true
} else {
loader.loadFileArchive(zipReader)
}
}
if tryDirect {
loader.loadFile(name, isOnlyRequestedFile, file)
}
}
}
func (loader *fileLoader) loadFileArchive(zipReader *zip.Reader) {
var wg sync.WaitGroup
for _, file := range zipReader.File {
wg.Add(1)
go func(entry *zip.File) {
defer wg.Done()
entryFile, err := entry.Open()
if err != nil {
return
}
defer func() {
_ = entryFile.Close()
}()
loader.loadFile(entry.Name, false, entryFile)
}(file)
}
wg.Wait()
}
func (loader *fileLoader) loadFile(name string, isOnlyStagedFile bool, file io.Reader) {
fileData, err := ioutil.ReadAll(file)
if err != nil {
loader.markFailedFile()
}
reader, err := lgres.ReaderFrom(bytes.NewReader(fileData))
filename := filepath.Base(name)
if (err == nil) && (isOnlyStagedFile || fileAllowlist.Matches(filename)) {
location := FileLocation{DirPath: filepath.Dir(name), Name: filename}
loader.modify(func() {
if stateView, stateErr := reader.View(ids.GameState); (stateErr == nil) && archive.IsSavegame(stateView) {
loader.result.Savegames[location] = reader
} else {
loader.result.Resources[location] = reader
}
})
}
if strings.ToLower(filename) == ObjectPropertiesFilename {
decoder := serial.NewDecoder(bytes.NewReader(fileData))
properties := object.StandardPropertiesTable()
properties.Code(decoder)
err = decoder.FirstError()
if err == nil {
loader.modify(func() { loader.result.ObjectProperties = properties })
}
}
if strings.ToLower(filename) == TexturePropertiesFilename && (len(fileData) > 4) {
decoder := serial.NewDecoder(bytes.NewReader(fileData))
entryCount := (len(fileData) - 4) / texture.PropertiesSize
properties := make(texture.PropertiesList, entryCount)
properties.Code(decoder)
err = decoder.FirstError()
if err == nil {
loader.modify(func() { loader.result.TextureProperties = properties })
}
}
if err != nil {
loader.markFailedFile()
}
}
func (loader *fileLoader) markFailedFile() {
loader.modify(func() { loader.result.FailedFiles++ })
}
func (loader *fileLoader) modify(modifier func()) {
loader.resultMutex.Lock()
defer loader.resultMutex.Unlock()
modifier()
}