Skip to content

Commit

Permalink
feat: big refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
promiseofcake committed Sep 11, 2024
1 parent 0707fbb commit 625b87f
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 55 deletions.
12 changes: 7 additions & 5 deletions cmd/engine/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/promiseofcake/artifactsmmo-engine/internal/actions"
"github.com/promiseofcake/artifactsmmo-engine/internal/engine"
"github.com/promiseofcake/artifactsmmo-engine/internal/logging"
"github.com/promiseofcake/artifactsmmo-engine/internal/models"
)

func init() {
Expand All @@ -33,9 +34,10 @@ const (
)

type Config struct {
Token string `mapstructure:"token"`
LogLevel int `mapstructure:"log_level"`
Characters []Character `mapstructure:"characters"`
Token string `mapstructure:"token"`
LogLevel int `mapstructure:"log_level"`
Characters []Character `mapstructure:"characters"`
Orders models.SimpleItems `mapstructure:"orders"`
}

type Character struct {
Expand Down Expand Up @@ -74,15 +76,15 @@ func main() {

charCtx := logging.ContextWithLogger(ctx, slog.With("character", c.Name))
l := logging.Get(charCtx)
l.Info("starting BuildInventory engine", "actions", c.Actions)
l.Info("starting execute engine", "actions", c.Actions)

go func(charCtx context.Context) {
defer wg.Done()
err = blockInitialAction(charCtx, r, c.Name)
if err != nil {
log.Fatal(err)
}
err = engine.BuildInventory(charCtx, r, c.Name, c.Actions)
err = engine.Execute(charCtx, r, c.Name, c.Actions, cfg.Orders)
if err != nil {
log.Fatal(err)
}
Expand Down
84 changes: 76 additions & 8 deletions internal/actions/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ import (
)

// GetBankItems returns all items in the bank
func (r *Runner) GetBankItems(ctx context.Context) (models.BankItems, error) {
func (r *Runner) GetBankItems(ctx context.Context) (models.SimpleItems, error) {
resp, err := r.Client.GetBankItemsMyBankItemsGetWithResponse(ctx, &client.GetBankItemsMyBankItemsGetParams{})
if err != nil {
return models.BankItems{}, fmt.Errorf("failed to get bank items: %w", err)
return models.SimpleItems{}, fmt.Errorf("failed to get bank items: %w", err)
}

if resp.StatusCode() != http.StatusOK {
return models.BankItems{}, fmt.Errorf("failed to get bank items: %s (%d)", resp.Body, resp.StatusCode())
return models.SimpleItems{}, fmt.Errorf("failed to get bank items: %s (%d)", resp.Body, resp.StatusCode())
}

var bank models.BankItems
var bank models.SimpleItems
for _, i := range resp.JSON200.Data {
item := models.BankItem{
item := models.SimpleItem{
Code: i.Code,
Quantity: i.Quantity,
}
Expand Down Expand Up @@ -55,8 +55,44 @@ func (r *Runner) GetMyCharacterInfo(ctx context.Context, character string) (mode
return models.Character{}, fmt.Errorf("failed to find character: %s", character)
}

// GetMaps fetches world state based upon a given content type
func (r *Runner) GetMaps(ctx context.Context, contentType client.GetAllMapsMapsGetParamsContentType) (models.Locations, error) {
// GetMapsByContentCode fetches world state based upon a given content code
func (r *Runner) GetMapsByContentCode(ctx context.Context, contentCode string) (models.Locations, error) {
resp, err := r.Client.GetAllMapsMapsGetWithResponse(ctx, &client.GetAllMapsMapsGetParams{
ContentCode: &contentCode,
})
if err != nil {
return nil, fmt.Errorf("failed to fetch maps for content: %s %w", contentCode, err)
}

if resp.StatusCode() != http.StatusOK {
return nil, fmt.Errorf("failed to fetch maps: %s (%d)", resp.Body, resp.StatusCode())
}

var locs models.Locations
for _, l := range resp.JSON200.Data {
s, dataErr := l.Content.AsMapContentSchema()
if dataErr != nil {
return nil, fmt.Errorf("failed to extra map content schema: %w", err)
}

loc := models.Location{
Name: l.Name,
Skin: l.Skin,
Coords: models.Coords{
X: l.X,
Y: l.Y,
},
Code: s.Code,
Type: s.Type,
}

locs = append(locs, loc)
}
return locs, nil
}

// GetMapsByContentType fetches world state based upon a given content type
func (r *Runner) GetMapsByContentType(ctx context.Context, contentType client.GetAllMapsMapsGetParamsContentType) (models.Locations, error) {
resp, err := r.Client.GetAllMapsMapsGetWithResponse(ctx, &client.GetAllMapsMapsGetParams{
ContentType: &contentType,
})
Expand Down Expand Up @@ -174,7 +210,39 @@ func (r *Runner) GetMonsters(ctx context.Context, min, max int) (models.Monsters
return monsters, nil
}

func (r *Runner) GetResources(ctx context.Context, skill client.ResourceSchemaSkill, min, max int) (models.Resources, error) {
func (r *Runner) GetResourcesByDrop(ctx context.Context, drop string) (models.Resources, error) {
resp, err := r.Client.GetAllResourcesResourcesGetWithResponse(ctx, &client.GetAllResourcesResourcesGetParams{
Drop: &drop,
})
if err != nil {
return nil, fmt.Errorf("failed to fetch resources for drop %s, %w", drop, err)
}
if resp.StatusCode() != http.StatusOK {
return nil, fmt.Errorf("status failure (%d), message: %s", resp.StatusCode(), resp.Body)
}

var resources models.Resources
for _, res := range resp.JSON200.Data {

locations, lErr := r.GetMapsByContentCode(ctx, res.Code)
if lErr != nil || len(locations) == 0 {
return nil, fmt.Errorf("failed to find resource locations: %w", err)
}

resource := models.Resource{
Name: res.Name,
Code: res.Code,
Skill: res.Skill,
Level: res.Level,
Location: locations[0], // todo allow more locations
}
resources = append(resources, resource)
}

return resources, nil
}

func (r *Runner) GetResourcesBySkill(ctx context.Context, skill client.ResourceSchemaSkill, min, max int) (models.Resources, error) {
if min < 0 {
min = 0
}
Expand Down
53 changes: 23 additions & 30 deletions internal/engine/decision.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ import (
// ideally this is an event that is run until a stop value is returned
type Operation func(ctx context.Context, r *actions.Runner, character models.Character) bool

// BuildInventory commands a character to focus on building their inventory
// Execute commands a character to focus on building their inventory
// for harvestable items
func BuildInventory(ctx context.Context, r *actions.Runner, character string, actions []string) error {
func Execute(ctx context.Context, r *actions.Runner, character string, actions []string, orders models.SimpleItems) error {
l := logging.Get(ctx)

var operations []Operation
for _, op := range actions {
switch op {
case "bank":
operations = append(operations, bank)
case "gather":
operations = append(operations, gather)
// fallthrough
case "forage":
operations = append(operations, forage)
case "refine":
operations = append(operations, refine)
}
Expand All @@ -52,7 +52,19 @@ func BuildInventory(ctx context.Context, r *actions.Runner, character string, ac
l.Debug("operation loop canceled.")
return nil
default:
// TODO this isnt' right

l.Debug("checking for orders to fulfil", "orders", orders)
for _, o := range orders {
if ShouldFulfilOrder(ctx, r, o) {
l.Debug("order required to be fulfilled", "order", o)
oErr := FulfilOrder(ctx, r, character, o)
if oErr != nil {
l.Error("failed to fulfil order", "order", o, "error", oErr)
}
}
}

l.Debug("performing designated tasks", "tasks", operations)
currentIndex = (currentIndex + 1) % len(operations)
for !operations[currentIndex](ctx, r, c) {
select {
Expand All @@ -68,39 +80,20 @@ func BuildInventory(ctx context.Context, r *actions.Runner, character string, ac
}

// Operation loops
func bank(ctx context.Context, r *actions.Runner, character models.Character) bool {
l := logging.Get(ctx)
for {
select {
case <-ctx.Done():
l.Debug("banking context closed")
return true
default:
l.Debug("banking")
err := DepositAll(ctx, r, character.Name)
if err != nil {
panic(err)
}
l.Debug("banking done")
return true
}
}
}

func gather(ctx context.Context, r *actions.Runner, character models.Character) bool {
func forage(ctx context.Context, r *actions.Runner, character models.Character) bool {
l := logging.Get(ctx)
for {
select {
case <-ctx.Done():
l.Debug("gather context closed")
l.Debug("foraging context closed")
return true
default:
l.Debug("gathering")
err := Gather(ctx, r, character.Name)
l.Debug("foraging")
err := Forage(ctx, r, character.Name)
if err != nil {
panic(err)
}
l.Debug("gathering done")
l.Debug("foraging done")
return true
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/engine/fight.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func Fight(ctx context.Context, r *actions.Runner, character string) error {
return err
}

monsterLocations, err := r.GetMaps(ctx, client.Monster)
monsterLocations, err := r.GetMapsByContentType(ctx, client.Monster)
if err != nil {
l.Error("failed to get monster locations", "error", err)
return err
Expand Down
29 changes: 21 additions & 8 deletions internal/engine/gather.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@ import (
"github.com/promiseofcake/artifactsmmo-engine/internal/models"
)

// Gather will attempt to Gather resources until the character should bank
func Gather(ctx context.Context, r *actions.Runner, character string) error {
// Forage will attempt to Forage resources until the character should bank
func Forage(ctx context.Context, r *actions.Runner, character string) error {
l := logging.Get(ctx)
c, err := r.GetMyCharacterInfo(ctx, character)
if err != nil {
l.Error("failed to get character", "error", err)
return err
}

resourceLoations, err := r.GetMaps(ctx, client.Resource)
resourceLoations, err := r.GetMapsByContentType(ctx, client.Resource)
if err != nil {
l.Error("failed to get resource locations", "error", err)
return err
}

skill := c.ChooseWeakestSkill()
resourceInfo, err := r.GetResources(ctx, skill.Code, skill.MinLevel, skill.CurrentLevel)
resourceInfo, err := r.GetResourcesBySkill(ctx, skill.Code, skill.MinLevel, skill.CurrentLevel)
if err != nil {
l.Error("failed to get resources", "error", err)
return err
Expand Down Expand Up @@ -60,13 +60,26 @@ func Gather(ctx context.Context, r *actions.Runner, character string) error {
// check if we should bank straight away
if c.ShouldBank() {
l.Debug("character will bank")
return nil
return DepositAll(ctx, r, character)
}

return Gather(ctx, r, character, resource)
}

// Gather will move to, and gather loop a resource
func Gather(ctx context.Context, r *actions.Runner, character string, resource models.Resource) error {
l := logging.Get(ctx)

c, err := r.GetMyCharacterInfo(ctx, character)
if err != nil {
l.Error("failed to get character", "error", err)
return err
}

mErr := Move(ctx, r, character, resource.GetCoords())
if mErr != nil {
l.Error("failed to move", "error", err)
return err
l.Error("failed to move", "error", mErr)
return mErr
}

// harvest resource until we should stop
Expand All @@ -87,7 +100,7 @@ func Gather(ctx context.Context, r *actions.Runner, character string) error {

if c.ShouldBank() {
l.Debug("character will bank")
return nil
return DepositAll(ctx, r, character)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion internal/engine/movement.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func Move(ctx context.Context, r *actions.Runner, character string, coords model
// Travel facilitates travel to the nearest location for a given type/code
func Travel(ctx context.Context, r *actions.Runner, character string, location models.Location) error {
l := logging.Get(ctx)
maps, err := r.GetMaps(ctx, client.GetAllMapsMapsGetParamsContentType(location.Type))
maps, err := r.GetMapsByContentType(ctx, client.GetAllMapsMapsGetParamsContentType(location.Type))
if err != nil {
l.Error("failed to get maps", "error", err)
return err
Expand Down
70 changes: 70 additions & 0 deletions internal/engine/order.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package engine

import (
"context"
"fmt"

"github.com/promiseofcake/artifactsmmo-engine/internal/actions"
"github.com/promiseofcake/artifactsmmo-engine/internal/logging"
"github.com/promiseofcake/artifactsmmo-engine/internal/models"
)

func ShouldFulfilOrder(ctx context.Context, r *actions.Runner, order models.SimpleItem) bool {
// determine what's in the bank
items, err := r.GetBankItems(ctx)
if err != nil {
return false
}

var bankItem models.SimpleItem
for _, item := range items {
if item.Code == order.Code {
bankItem = item
break
}
}

logging.Get(ctx).Debug("")

if bankItem.Quantity < order.Quantity {
logging.Get(ctx).Debug("order quantity is greater than quantity on hand", "resource", order.Code, "required", order.Quantity, "on_hand", bankItem.Quantity)
return true
} else {
return false
}

}

func FulfilOrder(ctx context.Context, r *actions.Runner, character string, order models.SimpleItem) error {
// determine all resources that drop the order
resources, err := r.GetResourcesByDrop(ctx, order.Code)
if err != nil {
return fmt.Errorf("get resources by drop: %w", err)
}

// get character location
c, err := r.GetMyCharacterInfo(ctx, character)
if err != nil {
return fmt.Errorf("get character info: %w", err)
}

if c.ShouldBank() {
dErr := DepositAll(ctx, r, character)
if dErr != nil {
return fmt.Errorf("failed to deposit all: %w", dErr)
}
}

// goto the nearest resource
gErr := Gather(ctx, r, character, resources[0])
if gErr != nil {
return fmt.Errorf("failed to gather resources: %w", gErr)
} else {
dErr := DepositAll(ctx, r, character)
if dErr != nil {
return fmt.Errorf("failed to deposit all: %w", dErr)
}
}

return nil
}
Loading

0 comments on commit 625b87f

Please sign in to comment.