287 lines
7.4 KiB
Go
287 lines
7.4 KiB
Go
package entity
|
|
|
|
import (
|
|
"github.com/mohae/deepcopy"
|
|
"mongo.games.com/game/gamesrv/slotspkg/internal/generic/errors"
|
|
"mongo.games.com/game/gamesrv/slotspkg/internal/module/shared"
|
|
"mongo.games.com/game/gamesrv/slotspkg/slots/desc"
|
|
)
|
|
|
|
// GetFeature finds feature by walking all nodes in node tree
|
|
func (e *Entity) GetFeature(featureID int64) *shared.Feature {
|
|
var f *shared.Feature
|
|
e.Walk(func(node *shared.Node) bool {
|
|
for _, feature := range node.Features {
|
|
if feature.ID == featureID {
|
|
f = feature
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
})
|
|
|
|
if f != nil {
|
|
return f
|
|
}
|
|
|
|
for _, feature := range e.NodeTree.ImageFeatures {
|
|
if feature.ID == featureID {
|
|
return feature
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetTypeFeatures finds features by walking all nodes in node tree
|
|
func (e *Entity) GetTypeFeatures(node *shared.Node, typ string) []*shared.Feature {
|
|
features := make([]*shared.Feature, 0)
|
|
for _, feature := range node.Features {
|
|
if feature.Type == typ {
|
|
features = append(features, feature)
|
|
}
|
|
}
|
|
return features
|
|
}
|
|
|
|
// AddFeature adds feature to node features
|
|
func (e *Entity) AddFeature(node *shared.Node) int64 {
|
|
e.NodeTree.Incr++
|
|
featureID := e.NodeTree.Incr
|
|
|
|
node.Features = append(node.Features, &shared.Feature{
|
|
NodeID: node.ID,
|
|
ID: featureID,
|
|
SpinType: node.SpinType,
|
|
NodeType: node.Type,
|
|
Lifetime: -1,
|
|
Visiable: true,
|
|
})
|
|
|
|
return featureID
|
|
}
|
|
|
|
// PruneNodeFeatures prune features that has no lifetime
|
|
func (e *Entity) PruneNodeFeatures(node *shared.Node) {
|
|
for index := 0; index < len(node.Features); index++ {
|
|
feature := node.Features[index]
|
|
if feature.Lifetime == 0 {
|
|
node.Features = append(node.Features[:index],
|
|
node.Features[index+1:]...)
|
|
e.DeleteCustom(feature.ID)
|
|
index--
|
|
}
|
|
}
|
|
}
|
|
|
|
// FeaturesPassTime decreases features' lifetime on specific node
|
|
func (e *Entity) FeaturesPassTime(node *shared.Node, n int64) {
|
|
features := node.Features
|
|
for _, feature := range features {
|
|
if feature.Lifetime > 0 {
|
|
if feature.Lifetime > n {
|
|
feature.Lifetime -= n
|
|
} else {
|
|
feature.Lifetime = 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// UpdateImageFeatures saves image info from features to image features
|
|
func (e *Entity) UpdateImageFeatures() {
|
|
e.updateImageFeaturesByNode()
|
|
e.updateImageFeaturesByFormation()
|
|
}
|
|
|
|
func (e *Entity) updateImageFeaturesByNode() {
|
|
var features []*shared.Feature
|
|
for _, feature := range e.CursorNode().Features {
|
|
if feature.Imageable && feature.SeqID == 0 {
|
|
features = append(features, feature)
|
|
}
|
|
}
|
|
|
|
nodeType := e.CursorNode().Type
|
|
for index := 0; index < len(e.NodeTree.ImageFeatures); index++ {
|
|
imageFeature := e.NodeTree.ImageFeatures[index]
|
|
if imageFeature.SeqID == 0 && imageFeature.NodeType == nodeType {
|
|
e.NodeTree.ImageFeatures = append(
|
|
e.NodeTree.ImageFeatures[:index],
|
|
e.NodeTree.ImageFeatures[index+1:]...)
|
|
e.DeleteCustom(imageFeature.ID)
|
|
index--
|
|
}
|
|
}
|
|
|
|
for _, feature := range features {
|
|
e.copyFeatureToImage(feature)
|
|
}
|
|
}
|
|
|
|
func (e *Entity) updateImageFeaturesByFormation() {
|
|
var features []*shared.Feature
|
|
for _, feature := range e.CursorNode().Features {
|
|
if feature.Imageable && feature.SeqID > 0 {
|
|
features = append(features, feature)
|
|
}
|
|
}
|
|
|
|
for _, feature := range features {
|
|
formationID := feature.FormationID
|
|
for index := 0; index < len(e.NodeTree.ImageFeatures); index++ {
|
|
imageFeature := e.NodeTree.ImageFeatures[index]
|
|
if imageFeature.SeqID > 0 && imageFeature.FormationID == formationID {
|
|
e.NodeTree.ImageFeatures = append(
|
|
e.NodeTree.ImageFeatures[:index],
|
|
e.NodeTree.ImageFeatures[index+1:]...)
|
|
e.DeleteCustom(imageFeature.ID)
|
|
index--
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, feature := range features {
|
|
e.copyFeatureToImage(feature)
|
|
}
|
|
}
|
|
|
|
func (e *Entity) copyFeatureToImage(feature *shared.Feature) {
|
|
custom := e.GetCustom(feature.ID)
|
|
|
|
e.NodeTree.Incr++
|
|
featureID := e.NodeTree.Incr
|
|
|
|
// deep copy feature
|
|
newFeature := deepcopy.Copy(feature).(*shared.Feature)
|
|
newFeature.ID = featureID
|
|
|
|
e.NodeTree.ImageFeatures = append(e.NodeTree.ImageFeatures, newFeature)
|
|
|
|
e.AddFeatureCustom(featureID, deepcopy.Copy(custom))
|
|
}
|
|
|
|
func (e *Entity) copyFeatureToNode(node *shared.Node, feature *shared.Feature) {
|
|
custom := e.GetCustom(feature.ID)
|
|
|
|
e.NodeTree.Incr++
|
|
featureID := e.NodeTree.Incr
|
|
|
|
// deep copy feature
|
|
newFeature := deepcopy.Copy(feature).(*shared.Feature)
|
|
newFeature.ID = featureID
|
|
newFeature.Imageable = false
|
|
newFeature.Lifetime = 0
|
|
|
|
node.Features = append(node.Features, newFeature)
|
|
|
|
e.AddFeatureCustom(featureID, deepcopy.Copy(custom))
|
|
}
|
|
|
|
// AttachFeatureToFormation attaches feature to formation by seq ID
|
|
func (e *Entity) AttachFeatureToFormation(feature *shared.Feature, seqID int64) {
|
|
formation := e.GetFormation(feature.NodeID, seqID)
|
|
feature.SeqID = seqID
|
|
feature.FormationID = formation.ID
|
|
}
|
|
|
|
// InitNextFeatures inits init symbols features for next node
|
|
func (e *Entity) InitNextFeatures() {
|
|
e.initNextFeaturesByNode()
|
|
e.initNextFeaturesByFormations()
|
|
}
|
|
|
|
func (e *Entity) initNextFeaturesByNode() {
|
|
nextNodeType := e.NextNode().Type
|
|
cursorNodeType := e.CursorNode().Type
|
|
if nextNodeType == cursorNodeType {
|
|
return
|
|
}
|
|
for _, imageFeature := range e.NodeTree.ImageFeatures {
|
|
if imageFeature.SeqID == 0 && imageFeature.NodeType == nextNodeType {
|
|
e.copyFeatureToNode(e.NextNode(), imageFeature)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (e *Entity) initNextFeaturesByFormations() {
|
|
for _, nextFormation := range e.NextNode().Formations {
|
|
e.genFormationFeatures(nextFormation)
|
|
}
|
|
}
|
|
|
|
func (e *Entity) genFormationFeatures(nextFormation *shared.Formation) {
|
|
var initFeatures []*shared.Feature
|
|
defer func() {
|
|
for _, initFeature := range initFeatures {
|
|
e.copyFeatureToNode(e.NextNode(), initFeature)
|
|
}
|
|
}()
|
|
|
|
desc := e.getNextFormationDesc(nextFormation)
|
|
if desc == nil { // No formation in next node
|
|
return
|
|
}
|
|
|
|
// Check same formation id form cursor node, no need to copy feature
|
|
for _, cursorFormation := range e.CursorNode().Formations {
|
|
if nextFormation.ID == cursorFormation.ID {
|
|
return
|
|
}
|
|
}
|
|
|
|
// Next node is progressed, just read history
|
|
if e.NextNode().ProgressValue > 0 {
|
|
initFeatures = e.getImageFeatures(e.NextNode(), desc)
|
|
return
|
|
}
|
|
|
|
method := e.getNexFormationMethod(e.NextNode(), desc)
|
|
|
|
// Switch method to get all kinds of init symbols source
|
|
switch method {
|
|
case initSymbolsMethodNone:
|
|
// do nothing
|
|
case initSymbolsMethodConst:
|
|
// do nothing
|
|
case initSymbolsMethodRandom:
|
|
// do nothing
|
|
case initSymbolsMethodCopy:
|
|
initFeatures = e.getCopyFeatures(e.NextNode(), desc)
|
|
case initSymbolsMethodImage:
|
|
initFeatures = e.getImageFeatures(e.NextNode(), desc)
|
|
default:
|
|
panic(errors.With(method).Errorf("unsupported init symbols method"))
|
|
}
|
|
}
|
|
|
|
func (e *Entity) getCopyFeatures(node *shared.Node, desc *desc.FormationSeqDesc) []*shared.Feature {
|
|
for {
|
|
node = e.GetNode(node.Parent)
|
|
if node.ID == e.NodeTree.Root {
|
|
return nil
|
|
}
|
|
if desc.SeqID > int64(len(node.Formations)) {
|
|
continue
|
|
}
|
|
var features []*shared.Feature
|
|
for _, feature := range node.Features { // Use seq ID
|
|
if feature.SeqID == node.Formations[desc.SeqID-1].SeqID {
|
|
features = append(features, feature)
|
|
}
|
|
}
|
|
return features
|
|
}
|
|
}
|
|
|
|
func (e *Entity) getImageFeatures(node *shared.Node, desc *desc.FormationSeqDesc) []*shared.Feature {
|
|
var features []*shared.Feature
|
|
formation := node.Formations[desc.SeqID-1]
|
|
for _, imageFeature := range e.NodeTree.ImageFeatures { // Use formation ID
|
|
if imageFeature.SeqID > 0 && imageFeature.FormationID == formation.ID {
|
|
features = append(features, imageFeature)
|
|
}
|
|
}
|
|
return features
|
|
}
|