mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-04 07:37:48 -05:00
c52c6648dd
Systems now place all of their component factories into a `Components` member. This improves code readability and makes it clear when we are dealing specifically with ecs components. The concrete ComponentFactory instances now have `Add` and `Get` methods (as opposed to `AddAlpha` or `GetAlpha`). This enforces naming of component factories as to avoid collisions when embedded in a struct with other components. Also, the ComponentFactory interface is embedded directly into the concrete component factory without a name.
150 lines
4.2 KiB
Go
150 lines
4.2 KiB
Go
package d2systems
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
|
|
|
"github.com/gravestench/akara"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
|
)
|
|
|
|
// static check that the game config system implements the system interface
|
|
var _ akara.System = &GameConfigSystem{}
|
|
|
|
const (
|
|
loggerPrefixGameConfig = "Game Config"
|
|
)
|
|
|
|
// GameConfigSystem is responsible for game config configFileBootstrap procedure, as well as
|
|
// clearing the `Dirty` component of game configs. In the `configFileBootstrap` method of this system
|
|
// you can see that this system will add entities for the directories it expects config files
|
|
// to be found in, and it also adds an entity for the initial config file to be loaded.
|
|
//
|
|
// This system is dependant on the FileTypeResolver, FileSourceResolver, and
|
|
// FileHandleResolver sceneSystems because this system subscribes to entities
|
|
// with components created by these other sceneSystems. Nothing will break if these
|
|
// other sceneSystems are not present in the world, but no config files will be loaded by
|
|
// this system either...
|
|
type GameConfigSystem struct {
|
|
akara.BaseSubscriberSystem
|
|
*d2util.Logger
|
|
filesToCheck *akara.Subscription
|
|
gameConfigs *akara.Subscription
|
|
Components struct {
|
|
GameConfig d2components.GameConfigFactory
|
|
File d2components.FileFactory
|
|
FileType d2components.FileTypeFactory
|
|
FileHandle d2components.FileHandleFactory
|
|
FileSource d2components.FileSourceFactory
|
|
Dirty d2components.DirtyFactory
|
|
}
|
|
activeConfig *d2components.GameConfig
|
|
}
|
|
|
|
// Init the world with the necessary components related to game config files
|
|
func (m *GameConfigSystem) Init(world *akara.World) {
|
|
m.World = world
|
|
|
|
m.setupLogger()
|
|
|
|
m.Debug("initializing ...")
|
|
|
|
m.setupFactories()
|
|
m.setupSubscriptions()
|
|
}
|
|
|
|
func (m *GameConfigSystem) setupLogger() {
|
|
m.Logger = d2util.NewLogger()
|
|
m.SetPrefix(loggerPrefixGameConfig)
|
|
}
|
|
|
|
func (m *GameConfigSystem) setupFactories() {
|
|
m.Debug("setting up component factories")
|
|
|
|
m.InjectComponent(&d2components.File{}, &m.Components.File.ComponentFactory)
|
|
m.InjectComponent(&d2components.FileType{}, &m.Components.FileType.ComponentFactory)
|
|
m.InjectComponent(&d2components.FileHandle{}, &m.Components.FileHandle.ComponentFactory)
|
|
m.InjectComponent(&d2components.FileSource{}, &m.Components.FileSource.ComponentFactory)
|
|
m.InjectComponent(&d2components.GameConfig{}, &m.Components.GameConfig.ComponentFactory)
|
|
m.InjectComponent(&d2components.Dirty{}, &m.Components.Dirty.ComponentFactory)
|
|
}
|
|
|
|
func (m *GameConfigSystem) setupSubscriptions() {
|
|
m.Debug("setting up component subscriptions")
|
|
|
|
// we are going to check entities that dont yet have loaded asset types
|
|
filesToCheck := m.NewComponentFilter().
|
|
Require(
|
|
&d2components.File{},
|
|
&d2components.FileType{},
|
|
&d2components.FileHandle{},
|
|
).
|
|
Forbid(
|
|
&d2components.GameConfig{},
|
|
&d2components.StringTable{},
|
|
&d2components.DataDictionary{},
|
|
&d2components.Palette{},
|
|
&d2components.PaletteTransform{},
|
|
&d2components.Cof{},
|
|
&d2components.Dc6{},
|
|
&d2components.Dcc{},
|
|
&d2components.Ds1{},
|
|
&d2components.Dt1{},
|
|
&d2components.Wav{},
|
|
&d2components.AnimationData{},
|
|
).
|
|
Build()
|
|
|
|
// we are interested in actual game config instances, too
|
|
gameConfigs := m.NewComponentFilter().
|
|
Require(&d2components.GameConfig{}).
|
|
Build()
|
|
|
|
m.filesToCheck = m.AddSubscription(filesToCheck)
|
|
m.gameConfigs = m.AddSubscription(gameConfigs)
|
|
}
|
|
|
|
// Update checks for new config files
|
|
func (m *GameConfigSystem) Update() {
|
|
m.checkForNewConfig(m.filesToCheck.GetEntities())
|
|
}
|
|
|
|
func (m *GameConfigSystem) checkForNewConfig(entities []akara.EID) {
|
|
for _, eid := range entities {
|
|
fp, found := m.Components.File.Get(eid)
|
|
if !found {
|
|
continue
|
|
}
|
|
|
|
ft, found := m.Components.FileType.Get(eid)
|
|
if !found {
|
|
continue
|
|
}
|
|
|
|
if fp.Path != configFileName || ft.Type != d2enum.FileTypeJSON {
|
|
continue
|
|
}
|
|
|
|
m.Info("loading config file ...")
|
|
m.loadConfig(eid)
|
|
}
|
|
}
|
|
|
|
func (m *GameConfigSystem) loadConfig(eid akara.EID) {
|
|
fh, found := m.Components.FileHandle.Get(eid)
|
|
if !found {
|
|
return
|
|
}
|
|
|
|
gameConfig := m.Components.GameConfig.Add(eid)
|
|
|
|
if err := json.NewDecoder(fh.Data).Decode(gameConfig); err != nil {
|
|
m.RemoveEntity(eid)
|
|
}
|
|
|
|
m.activeConfig = gameConfig
|
|
}
|