mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-03 23:26:41 -05:00
adding d2util.Loggers instances to existing systems
This commit is contained in:
parent
e2bd1d8c71
commit
bdf3a2e75d
@ -1,6 +1,7 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"io"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
@ -29,14 +30,18 @@ const (
|
||||
assetCacheEntryWeight = 1 // may want to make different weights for different asset types
|
||||
)
|
||||
|
||||
const (
|
||||
LogPrefixAssetLoader = "Asset Loader System"
|
||||
)
|
||||
|
||||
// NewAssetLoader creates a new asset loader instance
|
||||
func NewAssetLoader() *AssetLoaderSystem {
|
||||
// we are going to check entities that dont yet have loaded asset types
|
||||
filesToLoad := akara.NewFilter().
|
||||
Require(d2components.FilePath).
|
||||
Require(d2components.FilePath). // we want to process entities with these file components
|
||||
Require(d2components.FileType).
|
||||
Require(d2components.FileHandle).
|
||||
Forbid(d2components.FileSource).
|
||||
Forbid(d2components.FileSource). // but we forbid files that are already loaded
|
||||
Forbid(d2components.GameConfig).
|
||||
Forbid(d2components.StringTable).
|
||||
Forbid(d2components.DataDictionary).
|
||||
@ -55,16 +60,22 @@ func NewAssetLoader() *AssetLoaderSystem {
|
||||
Require(d2components.FileSource).
|
||||
Build()
|
||||
|
||||
return &AssetLoaderSystem{
|
||||
assetLoader := &AssetLoaderSystem{
|
||||
SubscriberSystem: akara.NewSubscriberSystem(filesToLoad, fileSources),
|
||||
cache: d2cache.CreateCache(assetCacheBudget).(*d2cache.Cache),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
assetLoader.SetPrefix(LogPrefixAssetLoader)
|
||||
|
||||
return assetLoader
|
||||
}
|
||||
|
||||
var _ akara.System = &AssetLoaderSystem{}
|
||||
|
||||
type AssetLoaderSystem struct {
|
||||
*akara.SubscriberSystem
|
||||
*d2util.Logger
|
||||
fileSub *akara.Subscription
|
||||
sourceSub *akara.Subscription
|
||||
cache *d2cache.Cache
|
||||
@ -95,6 +106,8 @@ func (m *AssetLoaderSystem) Init(world *akara.World) {
|
||||
return
|
||||
}
|
||||
|
||||
m.Info("initializing ...")
|
||||
|
||||
for subIdx := range m.Subscriptions {
|
||||
m.Subscriptions[subIdx] = m.AddSubscription(m.Subscriptions[subIdx].Filter)
|
||||
}
|
||||
@ -130,29 +143,37 @@ func (m *AssetLoaderSystem) Process() {
|
||||
}
|
||||
|
||||
func (m *AssetLoaderSystem) loadAsset(id akara.EID) {
|
||||
// make sure everything is kosher
|
||||
fp, found := m.filePaths.GetFilePath(id)
|
||||
if !found {
|
||||
m.Errorf("filepath component not found for entity %d", id)
|
||||
return
|
||||
}
|
||||
|
||||
ft, found := m.fileTypes.GetFileType(id)
|
||||
if !found {
|
||||
m.Errorf("filetype component not found for entity %d", id)
|
||||
return
|
||||
}
|
||||
|
||||
fh, found := m.fileHandles.GetFileHandle(id)
|
||||
if !found {
|
||||
m.Errorf("filehandle component not found for entity %d", id)
|
||||
return
|
||||
}
|
||||
|
||||
if found := m.pullFromCache(id, fp.Path, ft.Type); found {
|
||||
// try to pull from the cache and assign to the given entity id
|
||||
if found := m.assignFromCache(id, fp.Path, ft.Type); found {
|
||||
m.Debugf("Retrieving %s from cache", fp.Path)
|
||||
return
|
||||
}
|
||||
|
||||
// make sure to seek back to 0 if the filehandle was cached
|
||||
_, _ = fh.Data.Seek(0, 0)
|
||||
|
||||
data, buf := make([]byte, 0), make([]byte, 16)
|
||||
|
||||
// read, parse, and cache the data
|
||||
for {
|
||||
numRead, err := fh.Data.Read(buf)
|
||||
data = append(data, buf[:numRead]...)
|
||||
@ -165,12 +186,13 @@ func (m *AssetLoaderSystem) loadAsset(id akara.EID) {
|
||||
m.parseAndCache(id, fp.Path, ft.Type, data)
|
||||
}
|
||||
|
||||
func (m *AssetLoaderSystem) pullFromCache(id akara.EID, path string, t d2enum.FileType) bool {
|
||||
func (m *AssetLoaderSystem) assignFromCache(id akara.EID, path string, t d2enum.FileType) bool {
|
||||
entry, found := m.cache.Retrieve(path)
|
||||
if !found {
|
||||
return found
|
||||
}
|
||||
|
||||
// if we found what we're looking for, create the appropriate component and assign what we retrieved
|
||||
switch t {
|
||||
case d2enum.FileTypeStringTable:
|
||||
m.stringTables.AddStringTable(id).TextDictionary = entry.(*d2tbl.TextDictionary)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
@ -24,6 +25,10 @@ const (
|
||||
fileHandleCacheEntryWeight = 1
|
||||
)
|
||||
|
||||
const (
|
||||
logPrefixFileHandleResolver = "File Handle Resolver"
|
||||
)
|
||||
|
||||
func NewFileHandleResolver() *FileHandleResolutionSystem {
|
||||
// this filter is for entities that have a file path and file type but no file handle.
|
||||
filesToSource := akara.NewFilter().
|
||||
@ -37,18 +42,20 @@ func NewFileHandleResolver() *FileHandleResolutionSystem {
|
||||
RequireOne(d2components.FileSource).
|
||||
Build()
|
||||
|
||||
configsToUse := akara.NewFilter().
|
||||
Require(d2components.GameConfig).
|
||||
Build()
|
||||
|
||||
return &FileHandleResolutionSystem{
|
||||
SubscriberSystem: akara.NewSubscriberSystem(filesToSource, sourcesToUse, configsToUse),
|
||||
fhr := &FileHandleResolutionSystem{
|
||||
SubscriberSystem: akara.NewSubscriberSystem(filesToSource, sourcesToUse),
|
||||
cache: d2cache.CreateCache(fileHandleCacheBudget).(*d2cache.Cache),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
fhr.SetPrefix(logPrefixFileHandleResolver)
|
||||
|
||||
return fhr
|
||||
}
|
||||
|
||||
type FileHandleResolutionSystem struct {
|
||||
*akara.SubscriberSystem
|
||||
*d2util.Logger
|
||||
cache *d2cache.Cache
|
||||
filesToLoad *akara.Subscription
|
||||
sourcesToUse *akara.Subscription
|
||||
@ -62,15 +69,17 @@ type FileHandleResolutionSystem struct {
|
||||
func (m *FileHandleResolutionSystem) Init(world *akara.World) {
|
||||
m.World = world
|
||||
|
||||
for subIdx := range m.Subscriptions {
|
||||
m.Subscriptions[subIdx] = m.AddSubscription(m.Subscriptions[subIdx].Filter)
|
||||
}
|
||||
|
||||
if world == nil {
|
||||
m.SetActive(false)
|
||||
return
|
||||
}
|
||||
|
||||
for subIdx := range m.Subscriptions {
|
||||
m.Subscriptions[subIdx] = m.AddSubscription(m.Subscriptions[subIdx].Filter)
|
||||
}
|
||||
|
||||
m.Info("initializing ...")
|
||||
|
||||
m.filesToLoad = m.Subscriptions[0]
|
||||
m.sourcesToUse = m.Subscriptions[1]
|
||||
|
||||
@ -169,7 +178,7 @@ func (m *FileHandleResolutionSystem) loadFileWithSource(fileID, sourceID akara.E
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Printf("%s -> %s\n", sourceFp.Path, fp.Path)
|
||||
m.Infof("resolved `%s` with source `%s`", fp.Path, sourceFp.Path)
|
||||
|
||||
component := m.fileHandles.AddFileHandle(fileID)
|
||||
component.Data = data
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -13,6 +14,10 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
)
|
||||
|
||||
const (
|
||||
logPrefixFileSourceResolver = "File Source Resolver"
|
||||
)
|
||||
|
||||
func NewFileSourceResolver() *FileSourceResolver {
|
||||
// subscribe to entities with a file type and file path, but no file source type
|
||||
filesToCheck := akara.NewFilter().
|
||||
@ -21,13 +26,19 @@ func NewFileSourceResolver() *FileSourceResolver {
|
||||
Forbid(d2components.FileSource).
|
||||
Build()
|
||||
|
||||
return &FileSourceResolver{
|
||||
fsr := &FileSourceResolver{
|
||||
SubscriberSystem: akara.NewSubscriberSystem(filesToCheck),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
fsr.SetPrefix(logPrefixFileSourceResolver)
|
||||
|
||||
return fsr
|
||||
}
|
||||
|
||||
type FileSourceResolver struct {
|
||||
*akara.SubscriberSystem
|
||||
*d2util.Logger
|
||||
fileSub *akara.Subscription
|
||||
filePaths *d2components.FilePathMap
|
||||
fileTypes *d2components.FileTypeMap
|
||||
@ -43,6 +54,8 @@ func (m *FileSourceResolver) Init(world *akara.World) {
|
||||
return
|
||||
}
|
||||
|
||||
m.Info("initializing ...")
|
||||
|
||||
for subIdx := range m.Subscriptions {
|
||||
m.Subscriptions[subIdx] = m.AddSubscription(m.Subscriptions[subIdx].Filter)
|
||||
}
|
||||
@ -60,13 +73,12 @@ func (m *FileSourceResolver) Init(world *akara.World) {
|
||||
func (m *FileSourceResolver) Process() {
|
||||
for subIdx := range m.Subscriptions {
|
||||
for _, sourceEntityID := range m.Subscriptions[subIdx].GetEntities() {
|
||||
m.ProcessEntity(sourceEntityID)
|
||||
m.processSourceEntity(sourceEntityID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessEntity updates an individual entity in the system
|
||||
func (m *FileSourceResolver) ProcessEntity(id akara.EID) {
|
||||
func (m *FileSourceResolver) processSourceEntity(id akara.EID) {
|
||||
fp, found := m.filePaths.GetFilePath(id)
|
||||
if !found {
|
||||
return
|
||||
@ -79,9 +91,9 @@ func (m *FileSourceResolver) ProcessEntity(id akara.EID) {
|
||||
|
||||
switch ft.Type {
|
||||
case d2enum.FileTypeUnknown:
|
||||
m.Errorf("unknown file type for file `%s`", fp.Path)
|
||||
return
|
||||
case d2enum.FileTypeMPQ:
|
||||
source := m.fileSources.AddFileSource(id)
|
||||
instance, err := m.makeMpqSource(fp.Path)
|
||||
|
||||
if err != nil {
|
||||
@ -89,9 +101,11 @@ func (m *FileSourceResolver) ProcessEntity(id akara.EID) {
|
||||
break
|
||||
}
|
||||
|
||||
source := m.fileSources.AddFileSource(id)
|
||||
|
||||
m.Infof("creating MPQ source for `%s`", fp.Path)
|
||||
source.AbstractSource = instance
|
||||
case d2enum.FileTypeDirectory:
|
||||
source := m.fileSources.AddFileSource(id)
|
||||
instance, err := m.makeFileSystemSource(fp.Path)
|
||||
|
||||
if err != nil {
|
||||
@ -99,6 +113,9 @@ func (m *FileSourceResolver) ProcessEntity(id akara.EID) {
|
||||
break
|
||||
}
|
||||
|
||||
source := m.fileSources.AddFileSource(id)
|
||||
|
||||
m.Infof("creating FILESYSTEM source for `%s`", fp.Path)
|
||||
source.AbstractSource = instance
|
||||
}
|
||||
}
|
||||
@ -125,6 +142,10 @@ func (s *fsSource) fullPath(path string) string {
|
||||
return filepath.Clean(filepath.Join(s.rootDir, path))
|
||||
}
|
||||
|
||||
func (s *fsSource) Path() string {
|
||||
return filepath.Clean(s.rootDir)
|
||||
}
|
||||
|
||||
// mpq source
|
||||
func (m *FileSourceResolver) makeMpqSource(path string) (d2components.AbstractSource, error) {
|
||||
mpq, err := d2mpq.Load(path)
|
||||
@ -157,3 +178,7 @@ func (s *mpqSource) cleanMpqPath(path string) string {
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func (s *mpqSource) Path() string {
|
||||
return filepath.Clean(s.mpq.Path())
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -12,6 +13,10 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
)
|
||||
|
||||
const (
|
||||
logPrefixFileTypeResolver = "File Type Resolver"
|
||||
)
|
||||
|
||||
// NewFileTypeResolver creates a new file type resolution system.
|
||||
func NewFileTypeResolver() *FileTypeResolver {
|
||||
// we subscribe only to entities that have a filepath
|
||||
@ -21,9 +26,14 @@ func NewFileTypeResolver() *FileTypeResolver {
|
||||
Forbid(d2components.FileType).
|
||||
Build()
|
||||
|
||||
return &FileTypeResolver{
|
||||
ftr := &FileTypeResolver{
|
||||
SubscriberSystem: akara.NewSubscriberSystem(filesToCheck),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
ftr.SetPrefix(logPrefixFileTypeResolver)
|
||||
|
||||
return ftr
|
||||
}
|
||||
|
||||
// static check that FileTypeResolver implements the System interface
|
||||
@ -36,6 +46,7 @@ var _ akara.System = &FileTypeResolver{}
|
||||
// from its subscription.
|
||||
type FileTypeResolver struct {
|
||||
*akara.SubscriberSystem
|
||||
*d2util.Logger
|
||||
filesToCheck *akara.Subscription
|
||||
filePaths *d2components.FilePathMap
|
||||
fileTypes *d2components.FileTypeMap
|
||||
@ -50,6 +61,8 @@ func (m *FileTypeResolver) Init(world *akara.World) {
|
||||
return
|
||||
}
|
||||
|
||||
m.Info("initializing ...")
|
||||
|
||||
for subIdx := range m.Subscriptions {
|
||||
m.Subscriptions[subIdx] = m.AddSubscription(m.Subscriptions[subIdx].Filter)
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/gravestench/akara"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
)
|
||||
|
||||
@ -14,82 +14,89 @@ const (
|
||||
configFileName = "config.json"
|
||||
)
|
||||
|
||||
const (
|
||||
LoggerPrefixBootstrap = "Bootstrap System"
|
||||
)
|
||||
|
||||
// static check that the game config system implements the system interface
|
||||
var _ akara.System = &GameBootstrapSystem{}
|
||||
|
||||
func NewGameBootstrapSystem() *GameBootstrapSystem {
|
||||
// we are going to check entities that dont yet have loaded asset types
|
||||
thingsToCheck := akara.NewFilter().
|
||||
Require(d2components.FilePath).
|
||||
Require(d2components.FileType).
|
||||
Require(d2components.FileHandle).
|
||||
Forbid(d2components.GameConfig).
|
||||
Forbid(d2components.StringTable).
|
||||
Forbid(d2components.DataDictionary).
|
||||
Forbid(d2components.Palette).
|
||||
Forbid(d2components.PaletteTransform).
|
||||
Forbid(d2components.Cof).
|
||||
Forbid(d2components.Dc6).
|
||||
Forbid(d2components.Dcc).
|
||||
Forbid(d2components.Ds1).
|
||||
Forbid(d2components.Dt1).
|
||||
Forbid(d2components.Wav).
|
||||
Forbid(d2components.AnimData).
|
||||
filesToCheck := akara.NewFilter().
|
||||
Require( // files that need to be loaded
|
||||
d2components.FileType,
|
||||
d2components.FileHandle,
|
||||
d2components.FilePath,
|
||||
).
|
||||
Forbid( // files which have been loaded
|
||||
d2components.GameConfig,
|
||||
d2components.StringTable,
|
||||
d2components.DataDictionary,
|
||||
d2components.Palette,
|
||||
d2components.PaletteTransform,
|
||||
d2components.Cof,
|
||||
d2components.Dc6,
|
||||
d2components.Dcc,
|
||||
d2components.Ds1,
|
||||
d2components.Dt1,
|
||||
d2components.Wav,
|
||||
d2components.AnimData,
|
||||
).
|
||||
Build()
|
||||
|
||||
// we are interested in actual game config instances, too
|
||||
gameConfigs := akara.NewFilter().Require(d2components.GameConfig).Build()
|
||||
|
||||
gcs := &GameBootstrapSystem{
|
||||
SubscriberSystem: akara.NewSubscriberSystem(thingsToCheck, gameConfigs),
|
||||
maps: struct {
|
||||
gameConfigs *d2components.GameConfigMap
|
||||
filePaths *d2components.FilePathMap
|
||||
fileTypes *d2components.FileTypeMap
|
||||
fileHandles *d2components.FileHandleMap
|
||||
fileSources *d2components.FileSourceMap
|
||||
}{},
|
||||
bootstrapSys := &GameBootstrapSystem{
|
||||
SubscriberSystem: akara.NewSubscriberSystem(filesToCheck, gameConfigs),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
return gcs
|
||||
bootstrapSys.SetPrefix(LoggerPrefixBootstrap)
|
||||
bootstrapSys.Debug("Created")
|
||||
|
||||
return bootstrapSys
|
||||
}
|
||||
|
||||
// GameBootstrapSystem is responsible for setting up the regular diablo2 game launch
|
||||
type GameBootstrapSystem struct {
|
||||
*akara.SubscriberSystem
|
||||
filesToCheck *akara.Subscription
|
||||
gameConfigs *akara.Subscription
|
||||
maps struct {
|
||||
gameConfigs *d2components.GameConfigMap
|
||||
filePaths *d2components.FilePathMap
|
||||
fileTypes *d2components.FileTypeMap
|
||||
fileHandles *d2components.FileHandleMap
|
||||
fileSources *d2components.FileSourceMap
|
||||
}
|
||||
*d2util.Logger
|
||||
subscribedFiles *akara.Subscription
|
||||
subscribedConfigs *akara.Subscription
|
||||
*d2components.GameConfigMap
|
||||
*d2components.FilePathMap
|
||||
*d2components.FileTypeMap
|
||||
*d2components.FileHandleMap
|
||||
*d2components.FileSourceMap
|
||||
}
|
||||
|
||||
func (m *GameBootstrapSystem) Init(world *akara.World) {
|
||||
m.World = world
|
||||
|
||||
if world == nil {
|
||||
m.Error("world is nil, deactivating.")
|
||||
m.SetActive(false)
|
||||
return
|
||||
}
|
||||
|
||||
m.Info("initializing ...")
|
||||
|
||||
for subIdx := range m.Subscriptions {
|
||||
m.Subscriptions[subIdx] = m.AddSubscription(m.Subscriptions[subIdx].Filter)
|
||||
}
|
||||
|
||||
m.filesToCheck = m.Subscriptions[0]
|
||||
m.gameConfigs = m.Subscriptions[1]
|
||||
m.subscribedFiles = m.Subscriptions[0]
|
||||
m.subscribedConfigs = m.Subscriptions[1]
|
||||
|
||||
// try to inject the components we require, then cast the returned
|
||||
// abstract ComponentMap back to the concrete implementation
|
||||
m.maps.filePaths = world.InjectMap(d2components.FilePath).(*d2components.FilePathMap)
|
||||
m.maps.fileTypes = world.InjectMap(d2components.FileType).(*d2components.FileTypeMap)
|
||||
m.maps.fileHandles = world.InjectMap(d2components.FileHandle).(*d2components.FileHandleMap)
|
||||
m.maps.fileSources = world.InjectMap(d2components.FileSource).(*d2components.FileSourceMap)
|
||||
m.maps.gameConfigs = world.InjectMap(d2components.GameConfig).(*d2components.GameConfigMap)
|
||||
m.GameConfigMap = world.InjectMap(d2components.GameConfig).(*d2components.GameConfigMap)
|
||||
m.FilePathMap = world.InjectMap(d2components.FilePath).(*d2components.FilePathMap)
|
||||
m.FileTypeMap = world.InjectMap(d2components.FileType).(*d2components.FileTypeMap)
|
||||
m.FileHandleMap = world.InjectMap(d2components.FileHandle).(*d2components.FileHandleMap)
|
||||
m.FileSourceMap = world.InjectMap(d2components.FileSource).(*d2components.FileSourceMap)
|
||||
|
||||
m.bootstrap()
|
||||
}
|
||||
@ -100,41 +107,58 @@ func (m *GameBootstrapSystem) bootstrap() {
|
||||
// we make two entities and assign file paths for the two directories that
|
||||
// we assume a config file may be inside of. These will be processed in the future by
|
||||
// the file type resolver system, and then the file source resolver system. At that point,
|
||||
// there will be sources for these two directories that can resolve the config file.
|
||||
// there will be sources for these two directories that can possibly resolve a config file.
|
||||
// A new config file is created if one is not found.
|
||||
|
||||
// make the two entities, these will be the file sources
|
||||
e1, e2 := m.NewEntity(), m.NewEntity()
|
||||
fp1, fp2 := m.maps.filePaths.AddFilePath(e1), m.maps.filePaths.AddFilePath(e2)
|
||||
|
||||
// the od2 directory has the highest priority
|
||||
fp1.Path = path.Dir(os.Args[0])
|
||||
// add file path components to these entities
|
||||
fp1, fp2 := m.AddFilePath(e1), m.AddFilePath(e2)
|
||||
|
||||
// the user config directory is second highest
|
||||
configDir, err := os.UserConfigDir()
|
||||
// the first entity gets a filepath for the od2 directory, this one is checked first
|
||||
// eg. if OD2 binary is in `~/src/OpenDiablo2/`, then this directory is checked first for a config file
|
||||
cfgPath1 := path.Dir(os.Args[0])
|
||||
fp1.Path = cfgPath1
|
||||
m.Infof("setting up local directory %s for processing", cfgPath1)
|
||||
|
||||
// now add the user config directory
|
||||
// this directory on a linux machine would be something like `~/.config/OpenDiablo2/`
|
||||
cfgPath2, err := os.UserConfigDir()
|
||||
if err == nil {
|
||||
fp2.Path = path.Join(configDir, configDirectoryName)
|
||||
fp2.Path = path.Join(cfgPath2, configDirectoryName)
|
||||
m.Infof("setting up user config directory %s for processing", fp2.Path)
|
||||
} else {
|
||||
// we couldn't find the directory
|
||||
// we couldn't find the directory, destroy this entity
|
||||
m.Error("user config directory not found, skipping")
|
||||
m.RemoveEntity(e2)
|
||||
}
|
||||
|
||||
// now we set up the config file to be loaded. this happens after the directories
|
||||
// above are recognized as file sources.
|
||||
e3 := m.NewEntity()
|
||||
fp3 := m.maps.filePaths.AddFilePath(e3)
|
||||
fp3.Path = configFileName
|
||||
// now that we have set up where we look for config files,
|
||||
// we need to make an entity for the config file we want to load
|
||||
m.AddFilePath(m.NewEntity()).Path = configFileName
|
||||
|
||||
// The actual processing of all of this happens when the world updates the systems.
|
||||
// this process may take more than one iteration over the systems
|
||||
}
|
||||
|
||||
func (m *GameBootstrapSystem) Process() {
|
||||
configs := m.gameConfigs.GetEntities()
|
||||
configs := m.subscribedConfigs.GetEntities()
|
||||
if len(configs) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
cfg, found := m.maps.gameConfigs.GetGameConfig(configs[0])
|
||||
m.Infof("found %d new configs to parse", len(configs))
|
||||
|
||||
firstConfigEntityID := configs[0]
|
||||
cfg, found := m.GetGameConfig(firstConfigEntityID)
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
m.initMpqSources(cfg)
|
||||
|
||||
m.Info("game bootstrap complete, deactivating system")
|
||||
m.SetActive(false) // bootstrap is complete!
|
||||
}
|
||||
|
||||
@ -142,8 +166,10 @@ func (m *GameBootstrapSystem) initMpqSources(cfg *d2components.GameConfigCompone
|
||||
for _, mpqFileName := range cfg.MpqLoadOrder {
|
||||
fullMpqFilePath := path.Join(cfg.MpqPath, mpqFileName)
|
||||
|
||||
m.Infof("adding mpq: %s", fullMpqFilePath)
|
||||
|
||||
// make a new entity for the mpq file source
|
||||
mpqSource := m.maps.filePaths.AddFilePath(m.NewEntity())
|
||||
mpqSource := m.AddFilePath(m.NewEntity())
|
||||
mpqSource.Path = fullMpqFilePath
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package d2systems
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
@ -13,9 +13,13 @@ import (
|
||||
// static check that the game config system implements the system interface
|
||||
var _ akara.System = &GameConfigSystem{}
|
||||
|
||||
const (
|
||||
loggerPrefixGameConfig = "Game Config"
|
||||
)
|
||||
|
||||
func NewGameConfigSystem() *GameConfigSystem {
|
||||
// we are going to check entities that dont yet have loaded asset types
|
||||
thingsToCheck := akara.NewFilter().
|
||||
filesToCheck := akara.NewFilter().
|
||||
Require(d2components.FilePath).
|
||||
Require(d2components.FileType).
|
||||
Require(d2components.FileHandle).
|
||||
@ -34,20 +38,17 @@ func NewGameConfigSystem() *GameConfigSystem {
|
||||
Build()
|
||||
|
||||
// we are interested in actual game config instances, too
|
||||
gameConfigs := akara.NewFilter().Require(d2components.GameConfig).Build()
|
||||
gameConfigs := akara.NewFilter().
|
||||
Require(d2components.GameConfig).
|
||||
Build()
|
||||
|
||||
gcs := &GameConfigSystem{
|
||||
SubscriberSystem: akara.NewSubscriberSystem(thingsToCheck, gameConfigs),
|
||||
maps: struct {
|
||||
gameConfigs *d2components.GameConfigMap
|
||||
filePaths *d2components.FilePathMap
|
||||
fileTypes *d2components.FileTypeMap
|
||||
fileHandles *d2components.FileHandleMap
|
||||
fileSources *d2components.FileSourceMap
|
||||
dirty *d2components.DirtyMap
|
||||
}{},
|
||||
SubscriberSystem: akara.NewSubscriberSystem(filesToCheck, gameConfigs),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
gcs.SetPrefix(loggerPrefixGameConfig)
|
||||
|
||||
return gcs
|
||||
}
|
||||
|
||||
@ -63,16 +64,15 @@ func NewGameConfigSystem() *GameConfigSystem {
|
||||
// this system either...
|
||||
type GameConfigSystem struct {
|
||||
*akara.SubscriberSystem
|
||||
*d2util.Logger
|
||||
filesToCheck *akara.Subscription
|
||||
gameConfigs *akara.Subscription
|
||||
maps struct {
|
||||
gameConfigs *d2components.GameConfigMap
|
||||
filePaths *d2components.FilePathMap
|
||||
fileTypes *d2components.FileTypeMap
|
||||
fileHandles *d2components.FileHandleMap
|
||||
fileSources *d2components.FileSourceMap
|
||||
dirty *d2components.DirtyMap
|
||||
}
|
||||
*d2components.GameConfigMap
|
||||
*d2components.FilePathMap
|
||||
*d2components.FileTypeMap
|
||||
*d2components.FileHandleMap
|
||||
*d2components.FileSourceMap
|
||||
*d2components.DirtyMap
|
||||
}
|
||||
|
||||
func (m *GameConfigSystem) Init(world *akara.World) {
|
||||
@ -83,6 +83,8 @@ func (m *GameConfigSystem) Init(world *akara.World) {
|
||||
return
|
||||
}
|
||||
|
||||
m.Info("initializing ...")
|
||||
|
||||
for subIdx := range m.Subscriptions {
|
||||
m.Subscriptions[subIdx] = m.AddSubscription(m.Subscriptions[subIdx].Filter)
|
||||
}
|
||||
@ -92,39 +94,26 @@ func (m *GameConfigSystem) Init(world *akara.World) {
|
||||
|
||||
// try to inject the components we require, then cast the returned
|
||||
// abstract ComponentMap back to the concrete implementation
|
||||
m.maps.filePaths = world.InjectMap(d2components.FilePath).(*d2components.FilePathMap)
|
||||
m.maps.fileTypes = world.InjectMap(d2components.FileType).(*d2components.FileTypeMap)
|
||||
m.maps.fileHandles = world.InjectMap(d2components.FileHandle).(*d2components.FileHandleMap)
|
||||
m.maps.fileSources = world.InjectMap(d2components.FileSource).(*d2components.FileSourceMap)
|
||||
m.maps.gameConfigs = world.InjectMap(d2components.GameConfig).(*d2components.GameConfigMap)
|
||||
m.maps.dirty = world.InjectMap(d2components.Dirty).(*d2components.DirtyMap)
|
||||
m.FilePathMap = world.InjectMap(d2components.FilePath).(*d2components.FilePathMap)
|
||||
m.FileTypeMap = world.InjectMap(d2components.FileType).(*d2components.FileTypeMap)
|
||||
m.FileHandleMap = world.InjectMap(d2components.FileHandle).(*d2components.FileHandleMap)
|
||||
m.FileSourceMap = world.InjectMap(d2components.FileSource).(*d2components.FileSourceMap)
|
||||
m.GameConfigMap = world.InjectMap(d2components.GameConfig).(*d2components.GameConfigMap)
|
||||
m.DirtyMap = world.InjectMap(d2components.Dirty).(*d2components.DirtyMap)
|
||||
}
|
||||
|
||||
func (m *GameConfigSystem) Process() {
|
||||
m.clearDirty(m.gameConfigs.GetEntities())
|
||||
m.checkForNewConfig(m.filesToCheck.GetEntities())
|
||||
}
|
||||
|
||||
func (m *GameConfigSystem) clearDirty(entities []akara.EID) {
|
||||
for _, eid := range entities {
|
||||
dc, found := m.maps.dirty.GetDirty(eid)
|
||||
if !found {
|
||||
m.maps.dirty.AddDirty(eid) // adds it, but it's false
|
||||
continue
|
||||
}
|
||||
|
||||
dc.IsDirty = false
|
||||
}
|
||||
}
|
||||
|
||||
func (m *GameConfigSystem) checkForNewConfig(entities []akara.EID) {
|
||||
for _, eid := range entities {
|
||||
fp, found := m.maps.filePaths.GetFilePath(eid)
|
||||
fp, found := m.GetFilePath(eid)
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
ft, found := m.maps.fileTypes.GetFileType(eid)
|
||||
ft, found := m.GetFileType(eid)
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
@ -133,20 +122,21 @@ func (m *GameConfigSystem) checkForNewConfig(entities []akara.EID) {
|
||||
continue
|
||||
}
|
||||
|
||||
m.Info("loading config file ...")
|
||||
m.loadConfig(eid)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *GameConfigSystem) loadConfig(eid akara.EID) {
|
||||
fh, found := m.maps.fileHandles.GetFileHandle(eid)
|
||||
fh, found := m.GetFileHandle(eid)
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
gameConfig := m.maps.gameConfigs.AddGameConfig(eid)
|
||||
gameConfig := m.AddGameConfig(eid)
|
||||
|
||||
if err := json.NewDecoder(fh.Data).Decode(gameConfig); err != nil {
|
||||
m.maps.gameConfigs.Remove(eid)
|
||||
m.GameConfigMap.Remove(eid)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -11,21 +11,13 @@ import (
|
||||
func Test_integration(t *testing.T) {
|
||||
cfg := akara.NewWorldConfig()
|
||||
|
||||
bootstrap := NewGameBootstrapSystem()
|
||||
fileTypeResolver := NewFileTypeResolver()
|
||||
fileHandleResolver := NewFileHandleResolver()
|
||||
fileSourceResolver := NewFileSourceResolver()
|
||||
gameConfig := NewGameConfigSystem()
|
||||
assetLoader := NewAssetLoader()
|
||||
renderer := NewRenderSystem()
|
||||
|
||||
cfg.With(fileTypeResolver).
|
||||
With(fileSourceResolver).
|
||||
With(fileHandleResolver).
|
||||
With(gameConfig).
|
||||
With(assetLoader).
|
||||
With(renderer).
|
||||
With(bootstrap)
|
||||
cfg.With(NewFileTypeResolver()).
|
||||
With(NewFileSourceResolver()).
|
||||
With(NewFileHandleResolver()).
|
||||
With(NewGameConfigSystem()).
|
||||
With(NewAssetLoader()).
|
||||
With(NewRenderSystem()).
|
||||
With(NewGameBootstrapSystem())
|
||||
|
||||
world := akara.NewWorld(cfg)
|
||||
|
||||
@ -43,11 +35,8 @@ func Test_integration(t *testing.T) {
|
||||
mm, _ := world.ComponentManager.GetMap(d2components.Dc6)
|
||||
dc6map := mm.(*d2components.Dc6Map)
|
||||
|
||||
updateCount := 0
|
||||
|
||||
for {
|
||||
world.Update(0)
|
||||
updateCount++
|
||||
_, found := dc6map.GetDc6(e1)
|
||||
|
||||
if found {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"time"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
@ -8,6 +9,10 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
)
|
||||
|
||||
const (
|
||||
logPrefixMovementSystem = "Movement System"
|
||||
)
|
||||
|
||||
// NewMovementSystem creates a movement system
|
||||
func NewMovementSystem() *MovementSystem {
|
||||
cfg := akara.NewFilter().Require(d2components.Position, d2components.Velocity)
|
||||
@ -16,6 +21,7 @@ func NewMovementSystem() *MovementSystem {
|
||||
|
||||
return &MovementSystem{
|
||||
SubscriberSystem: akara.NewSubscriberSystem(filter),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +31,7 @@ var _ akara.System = &MovementSystem{}
|
||||
// MovementSystem handles entity movement based on velocity and position components
|
||||
type MovementSystem struct {
|
||||
*akara.SubscriberSystem
|
||||
*d2util.Logger
|
||||
positions *d2components.PositionMap
|
||||
velocities *d2components.VelocityMap
|
||||
}
|
||||
@ -38,6 +45,8 @@ func (m *MovementSystem) Init(world *akara.World) {
|
||||
return
|
||||
}
|
||||
|
||||
m.Info("initializing ...")
|
||||
|
||||
for subIdx := range m.Subscriptions {
|
||||
m.Subscriptions[subIdx] = m.AddSubscription(m.Subscriptions[subIdx].Filter)
|
||||
}
|
||||
@ -52,6 +61,9 @@ func (m *MovementSystem) Init(world *akara.World) {
|
||||
func (m *MovementSystem) Process() {
|
||||
for subIdx := range m.Subscriptions {
|
||||
entities := m.Subscriptions[subIdx].GetEntities()
|
||||
|
||||
m.Infof("Processing movement for %d entities ...", len(entities))
|
||||
|
||||
for entIdx := range entities {
|
||||
m.ProcessEntity(entities[entIdx])
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
|
||||
"time"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
@ -13,6 +16,7 @@ import (
|
||||
|
||||
const (
|
||||
gameTitle = "Open Diablo 2"
|
||||
logPrefixRenderSystem = "Render System"
|
||||
)
|
||||
|
||||
// NewRenderSystem creates a movement system
|
||||
@ -20,9 +24,14 @@ func NewRenderSystem() *RenderSystem {
|
||||
viewports := akara.NewFilter().Require(d2components.ViewPort).Build()
|
||||
gameConfigs := akara.NewFilter().Require(d2components.GameConfig).Build()
|
||||
|
||||
return &RenderSystem{
|
||||
r := &RenderSystem{
|
||||
SubscriberSystem: akara.NewSubscriberSystem(viewports, gameConfigs),
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
r.SetPrefix(logPrefixRenderSystem)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// static check that RenderSystem implements the System interface
|
||||
@ -31,12 +40,13 @@ var _ akara.System = &RenderSystem{}
|
||||
// RenderSystem handles entity movement based on velocity and position components
|
||||
type RenderSystem struct {
|
||||
*akara.SubscriberSystem
|
||||
*d2util.Logger
|
||||
renderer d2interface.Renderer
|
||||
screenSurface d2interface.Surface
|
||||
viewports *akara.Subscription
|
||||
configs *akara.Subscription
|
||||
configMap *d2components.GameConfigMap
|
||||
viewportMap *d2components.ViewPortMap
|
||||
*d2components.GameConfigMap
|
||||
*d2components.ViewPortMap
|
||||
lastUpdate time.Time
|
||||
}
|
||||
|
||||
@ -49,6 +59,8 @@ func (m *RenderSystem) Init(world *akara.World) {
|
||||
return
|
||||
}
|
||||
|
||||
m.Info("initializing ...")
|
||||
|
||||
for subIdx := range m.Subscriptions {
|
||||
m.Subscriptions[subIdx] = m.AddSubscription(m.Subscriptions[subIdx].Filter)
|
||||
}
|
||||
@ -58,8 +70,8 @@ func (m *RenderSystem) Init(world *akara.World) {
|
||||
|
||||
// try to inject the components we require, then cast the returned
|
||||
// abstract ComponentMap back to the concrete implementation
|
||||
m.configMap = m.InjectMap(d2components.GameConfig).(*d2components.GameConfigMap)
|
||||
m.viewportMap = m.InjectMap(d2components.ViewPort).(*d2components.ViewPortMap)
|
||||
m.GameConfigMap = m.InjectMap(d2components.GameConfig).(*d2components.GameConfigMap)
|
||||
m.ViewPortMap = m.InjectMap(d2components.ViewPort).(*d2components.ViewPortMap)
|
||||
}
|
||||
|
||||
// Process will create a renderer if it doesnt exist yet,
|
||||
@ -68,14 +80,6 @@ func (m *RenderSystem) Process() {
|
||||
if m.renderer == nil {
|
||||
m.createRenderer()
|
||||
}
|
||||
|
||||
if m.screenSurface == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, eid := range m.viewports.GetEntities() {
|
||||
m.render(eid)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *RenderSystem) createRenderer() {
|
||||
@ -84,12 +88,28 @@ func (m *RenderSystem) createRenderer() {
|
||||
return
|
||||
}
|
||||
|
||||
config, found := m.configMap.GetGameConfig(configs[0])
|
||||
config, found := m.GetGameConfig(configs[0])
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
renderer, err := d2render.CreateRenderer()
|
||||
// d2render.CreateRenderer should use a GameConfigComponent instead ...
|
||||
oldStyleConfig := &d2config.Configuration{
|
||||
MpqLoadOrder: config.MpqLoadOrder,
|
||||
Language: config.Language,
|
||||
MpqPath: config.MpqPath,
|
||||
TicksPerSecond: config.TicksPerSecond,
|
||||
FpsCap: config.FpsCap,
|
||||
SfxVolume: config.SfxVolume,
|
||||
BgmVolume: config.BgmVolume,
|
||||
FullScreen: config.FullScreen,
|
||||
RunInBackground: config.RunInBackground,
|
||||
VsyncEnabled: config.VsyncEnabled,
|
||||
Backend: config.Backend,
|
||||
LogLevel: config.LogLevel,
|
||||
}
|
||||
|
||||
renderer, err := d2render.CreateRenderer(oldStyleConfig)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -105,23 +125,27 @@ func (m *RenderSystem) createRenderer() {
|
||||
|
||||
m.lastUpdate = time.Now()
|
||||
|
||||
_ = m.renderer.Run(m.wrapWorldUpdate, 800, 600, gameTitle)
|
||||
_ = m.renderer.Run(m.render, m.updateWorld, 800, 600, gameTitle)
|
||||
}
|
||||
|
||||
func (m *RenderSystem) render(id akara.EID) {
|
||||
vp, found := m.viewportMap.GetViewPort(id)
|
||||
if !found {
|
||||
return
|
||||
func (m *RenderSystem) render(screen d2interface.Surface) error {
|
||||
m.screenSurface = screen
|
||||
|
||||
for _, id := range m.viewports.GetEntities() {
|
||||
vp, found := m.GetViewPort(id)
|
||||
if !found {
|
||||
return errors.New("viewport not found")
|
||||
}
|
||||
|
||||
if m.screenSurface != nil {
|
||||
m.screenSurface.Render(vp.Surface)
|
||||
}
|
||||
}
|
||||
|
||||
if m.screenSurface != nil {
|
||||
_ = m.screenSurface.Render(vp.Surface)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *RenderSystem) wrapWorldUpdate(s d2interface.Surface) error {
|
||||
m.screenSurface = s
|
||||
|
||||
func (m *RenderSystem) updateWorld() error {
|
||||
currentTime := time.Now()
|
||||
elapsed := currentTime.Sub(m.lastUpdate)
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"time"
|
||||
|
||||
"github.com/gravestench/akara"
|
||||
@ -10,12 +11,19 @@ const (
|
||||
defaultScale float64 = 1
|
||||
)
|
||||
|
||||
const (
|
||||
logPrefixTimeScaleSystem = "Time Scale"
|
||||
)
|
||||
|
||||
// NewTimeScaleSystem creates a timescale system
|
||||
func NewTimeScaleSystem() *TimeScaleSystem {
|
||||
m := &TimeScaleSystem{
|
||||
BaseSystem: &akara.BaseSystem{},
|
||||
Logger: d2util.NewLogger(),
|
||||
}
|
||||
|
||||
m.SetPrefix(logPrefixTimeScaleSystem)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
@ -27,20 +35,28 @@ var _ akara.System = &TimeScaleSystem{}
|
||||
// up the game time without affecting the render rate.
|
||||
type TimeScaleSystem struct {
|
||||
*akara.BaseSystem
|
||||
*d2util.Logger
|
||||
scale float64
|
||||
lastScale float64
|
||||
}
|
||||
|
||||
// Init will initialize the TimeScale system
|
||||
func (t *TimeScaleSystem) Init(world *akara.World) {
|
||||
t.World = world
|
||||
|
||||
t.Info("initializing ...")
|
||||
|
||||
t.scale = defaultScale
|
||||
}
|
||||
|
||||
// Process scales the worlds time delta for this frame
|
||||
func (t *TimeScaleSystem) Process() {
|
||||
if !t.Active() {
|
||||
if !t.Active() || t.scale == t.lastScale{
|
||||
return
|
||||
}
|
||||
|
||||
t.Infof("setting time scale to %.1f", t.scale)
|
||||
t.lastScale = t.scale
|
||||
|
||||
t.World.TimeDelta *= time.Duration(t.scale)
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@ -6,10 +6,10 @@ require (
|
||||
github.com/JoshVarga/blast v0.0.0-20180421040937-681c804fb9f0
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
|
||||
github.com/davecgh/go-spew v1.1.0
|
||||
github.com/go-restruct/restruct v1.2.0-alpha
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/gravestench/akara v0.0.0-20201014060234-a64208a7fd3c
|
||||
github.com/hajimehoshi/ebiten v1.12.3
|
||||
github.com/hajimehoshi/ebiten/v2 v2.0.0
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/profile v1.5.0
|
||||
|
9
go.sum
9
go.sum
@ -15,11 +15,15 @@ github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSr
|
||||
github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk=
|
||||
github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY=
|
||||
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gravestench/akara v0.0.0-20201014060234-a64208a7fd3c h1:WopE590cKxkcKXcOee4gPXHqtzwbarLClCaWNCdLqgI=
|
||||
github.com/gravestench/akara v0.0.0-20201014060234-a64208a7fd3c/go.mod h1:fTeda1SogMg5Lkd4lXMEd/Pk/a5/gQuLGaAI2rn1PBQ=
|
||||
github.com/hajimehoshi/bitmapfont v1.3.0/go.mod h1:/Qb7yVjHYNUV4JdqNkPs6BSZwLjKqkZOMIp6jZD0KgE=
|
||||
github.com/hajimehoshi/bitmapfont/v2 v2.1.0/go.mod h1:2BnYrkTQGThpr/CY6LorYtt/zEPNzvE/ND69CRTaHMs=
|
||||
github.com/hajimehoshi/ebiten v1.12.3 h1:/KYCLW5VvfMKOMb8TqjKFlDCQAibM+OiA+LUwjS8t0E=
|
||||
github.com/hajimehoshi/ebiten v1.12.3/go.mod h1:9JW9BAz1+swszT0SXR8VUvNvDafs9VspevAcY+KPlV8=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.0.0 h1:G8mhkKFtnDPPZ/ChaGWx4Bm0NusYEcafGCJ8QLxEaYs=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.0.0/go.mod h1:hpZZQ/kk8DZqft7QsQ5hZLRQXHSZPdKnaa0tcJ3CZFE=
|
||||
github.com/hajimehoshi/file2byteslice v0.0.0-20200812174855-0e5e8a80490e/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE=
|
||||
@ -62,6 +66,7 @@ golang.org/x/exp v0.0.0-20201008143054-e3b2a7f2fdc7/go.mod h1:1phAWC201xIgDyaFpm
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200801110659-972c09e46d76/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
@ -86,6 +91,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM=
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201028215240-c5abc1b1d397 h1:YZ169h3kkKEXsueizzMwOT9AaiffbOa6oXSmUFJ4vxM=
|
||||
@ -94,9 +100,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9 h1:KOkk4e2xd5OeCDJGwacvr75ICCbCsShrHiqPEdsA9hg=
|
||||
golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201009162240-fcf82128ed91/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
Loading…
Reference in New Issue
Block a user