Skip to content

Commit

Permalink
WIP: Sim talents in bulk sim (#4205)
Browse files Browse the repository at this point in the history
* WIP: Sim talents in bulk sim

* Dont double sim and sort properly

* Fix styling

* Use proto.Equal for comparison
  • Loading branch information
ToxicKevinFerm authored Jan 30, 2024
1 parent 446df8f commit 9b66dc4
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 18 deletions.
10 changes: 10 additions & 0 deletions proto/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,12 @@ message BulkSimRequest {
BulkSettings bulk_settings = 2;
}

message TalentLoadout {
string talents_string = 1;
Glyphs glyphs = 2;
string name = 3;
}

message BulkSettings {
repeated ItemSpec items = 1;
bool combinations = 2;
Expand All @@ -451,6 +457,9 @@ message BulkSettings {
// Number of iterations per combo.
// If set to 0 the sim core decides the optimal iterations.
int32 iterations_per_combo = 11;
// Should sim talents as well
bool sim_talents = 12;
repeated TalentLoadout talents_to_sim = 13;
}

message BulkSimResult {
Expand All @@ -462,6 +471,7 @@ message BulkSimResult {
message BulkComboResult {
repeated ItemSpecWithSlot items_added = 1;
UnitMetrics unit_metrics = 2;
TalentLoadout talent_loadout = 3;
}

message ItemSpecWithSlot {
Expand Down
36 changes: 31 additions & 5 deletions sim/core/bulksim.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func (b *bulkSimRunner) Run(pctx context.Context, progress chan *proto.ProgressM

// Gemming for now can happen before slots are decided.
// We might have to add logic after slot decisions if we want to enforce keeping meta gem active.

if b.Request.BulkSettings.AutoGem {
for _, replaceItem := range b.Request.BulkSettings.Items {
itemData := ItemsByID[replaceItem.Id]
Expand Down Expand Up @@ -184,7 +185,29 @@ func (b *bulkSimRunner) Run(pctx context.Context, progress chan *proto.ProgressM
}
substitutedRequest, changeLog := createNewRequestWithSubstitution(b.Request.BaseSettings, sub, b.Request.BulkSettings.AutoEnchant)
if isValidEquipment(substitutedRequest.Raid.Parties[0].Players[0].Equipment) {
// Need to sim base dps of gear loudout
validCombos = append(validCombos, singleBulkSim{req: substitutedRequest, cl: changeLog, eq: sub})
// Todo(Netzone-GehennasEU): Make this its own step?
if !b.Request.BulkSettings.SimTalents {

} else {
var talentsToSim = b.Request.BulkSettings.GetTalentsToSim()

if len(talentsToSim) > 0 {
for _, talent := range talentsToSim {
sr := goproto.Clone(substitutedRequest).(*proto.RaidSimRequest)
cl := *changeLog
if sr.Raid.Parties[0].Players[0].TalentsString == talent.TalentsString && goproto.Equal(talent.Glyphs, sr.Raid.Parties[0].Players[0].Glyphs) {
continue
}

sr.Raid.Parties[0].Players[0].TalentsString = talent.TalentsString
sr.Raid.Parties[0].Players[0].Glyphs = talent.Glyphs
cl.TalentLoadout = talent
validCombos = append(validCombos, singleBulkSim{req: sr, cl: &cl, eq: sub})
}
}
}
}
}

Expand Down Expand Up @@ -275,10 +298,10 @@ func (b *bulkSimRunner) Run(pctx context.Context, progress chan *proto.ProgressM
um.Auras = nil
um.Resources = nil
um.Pets = nil

result.Results = append(result.Results, &proto.BulkComboResult{
ItemsAdded: r.ChangeLog.AddedItems,
UnitMetrics: um,
ItemsAdded: r.ChangeLog.AddedItems,
UnitMetrics: um,
TalentLoadout: r.ChangeLog.TalentLoadout,
})
}

Expand Down Expand Up @@ -337,6 +360,7 @@ func (b *bulkSimRunner) getRankedResults(pctx context.Context, validCombos []sin
for _, singleCombo := range validCombos {
<-tickets
singleSimProgress := make(chan *proto.ProgressMetrics)

// watches this progress and pushes up to main reporter.
go func(prog chan *proto.ProgressMetrics) {
var prevDone int32
Expand All @@ -352,6 +376,7 @@ func (b *bulkSimRunner) getRankedResults(pctx context.Context, validCombos []sin
// actually run the sim in here.
go func(sub singleBulkSim) {
// overwrite the requests iterations with the input for this function.

sub.req.SimOptions.Iterations = int32(iterations)
results <- &itemSubstitutionSimResult{
Request: sub.req,
Expand All @@ -374,7 +399,7 @@ func (b *bulkSimRunner) getRankedResults(pctx context.Context, validCombos []sin
cancel() // cancel reporter
return nil, nil, errors.New("simulation failed: " + result.Result.ErrorResult)
}
if !result.Substitution.HasItemReplacements() {
if !result.Substitution.HasItemReplacements() && result.ChangeLog.TalentLoadout == nil {
baseResult = result
}
rankedResults[i] = result
Expand Down Expand Up @@ -620,7 +645,8 @@ type itemWithSlot struct {
// raidSimRequestChangeLog stores a change log of which items were added and removed from the base
// equipment set.
type raidSimRequestChangeLog struct {
AddedItems []*proto.ItemSpecWithSlot
AddedItems []*proto.ItemSpecWithSlot
TalentLoadout *proto.TalentLoadout
}

// createNewRequestWithSubstitution creates a copy of the input RaidSimRequest and applis the given
Expand Down
119 changes: 115 additions & 4 deletions ui/core/components/individual_sim_ui/bulk_tab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import { TypedEvent } from "../../typed_event";

import { EventID } from '../../typed_event.js';

import { BulkComboResult, BulkSettings, ItemSpecWithSlot, ProgressMetrics } from "../../proto/api";
import { EquipmentSpec, Faction, GemColor, ItemSlot, ItemSpec, SimDatabase, SimEnchant, SimGem, SimItem, Spec } from "../../proto/common";
import { BulkComboResult, BulkSettings, ItemSpecWithSlot, ProgressMetrics, TalentLoadout } from "../../proto/api";
import { EquipmentSpec, Faction, GemColor, Glyphs, ItemSlot, ItemSpec, SimDatabase, SimEnchant, SimGem, SimItem, Spec } from "../../proto/common";

import { ItemData, ItemList, ItemRenderer, SelectorModal, SelectorModalTabs } from "../gear_picker";
import { SimTab } from "../sim_tab";

import { UIEnchant, UIGem, UIItem } from "../../proto/ui";
import { SavedTalents, UIEnchant, UIGem, UIItem } from "../../proto/ui";
import { EquippedItem } from "../../proto_utils/equipped_item";
import { Component } from "../component";
import { ResultsViewer } from "../results_viewer";
Expand Down Expand Up @@ -50,6 +50,7 @@ export class BulkGearJsonImporter<SpecType extends Spec> extends Importer {
}
this.close();
} catch (e: any) {
console.warn(e);
alert(e.toString());
}
}
Expand Down Expand Up @@ -81,6 +82,17 @@ class BulkSimResultRenderer {
parent.bodyElement.appendChild(itemsContainer);
parent.bodyElement.appendChild(dpsDivParent);

const talentText = document.createElement('p');
talentText.classList.add('talent-loadout-text')
if (result.talentLoadout && typeof result.talentLoadout === 'object') {
if (typeof result.talentLoadout.name === 'string') {
talentText.textContent = 'Talent loadout used: ' + result.talentLoadout.name;
}
} else {
talentText.textContent = 'Current talents'
}

dpsDiv.appendChild(talentText);
if (result.itemsAdded && result.itemsAdded.length > 0) {
const equipBtn = document.createElement('button');
equipBtn.textContent = 'Equip';
Expand All @@ -105,7 +117,7 @@ class BulkSimResultRenderer {
p.textContent = this.itemSlotName(is);
renderer.nameElem.appendChild(p);
}
} else {
} else if (!result.talentLoadout || typeof result.talentLoadout !== 'object') {
const p = document.createElement('p');
p.textContent = 'No changes - this is your currently equipped gear!';
parent.bodyElement.appendChild(p);
Expand Down Expand Up @@ -228,8 +240,10 @@ export class BulkTab extends SimTab {
private doCombos: boolean;
private fastMode: boolean;
private autoGem: boolean;
private simTalents: boolean;
private autoEnchant: boolean;
private defaultGems: SimGem[];
private savedTalents: TalentLoadout[];
private gemIconElements: HTMLImageElement[];

constructor(parentElem: HTMLElement, simUI: IndividualSimUI<Spec>) {
Expand All @@ -256,6 +270,8 @@ export class BulkTab extends SimTab {
this.fastMode = true;
this.autoGem = true;
this.autoEnchant = true;
this.savedTalents = [];
this.simTalents = false;
this.defaultGems = [UIGem.create(), UIGem.create(), UIGem.create(), UIGem.create()];
this.gemIconElements = [];
this.buildTabContent();
Expand All @@ -277,7 +293,9 @@ export class BulkTab extends SimTab {
this.doCombos = settings.combinations;
this.fastMode = settings.fastMode;
this.autoEnchant = settings.autoEnchant;
this.savedTalents = settings.talentsToSim;
this.autoGem = settings.autoGem;
this.simTalents = settings.simTalents;
this.defaultGems = new Array<SimGem>(
SimGem.create({ id: settings.defaultRedGem }),
SimGem.create({ id: settings.defaultYellowGem }),
Expand Down Expand Up @@ -311,6 +329,8 @@ export class BulkTab extends SimTab {
fastMode: this.fastMode,
autoEnchant: this.autoEnchant,
autoGem: this.autoGem,
simTalents: this.simTalents,
talentsToSim: this.savedTalents,
defaultRedGem: this.defaultGems[0].id,
defaultYellowGem: this.defaultGems[1].id,
defaultBlueGem: this.defaultGems[2].id,
Expand Down Expand Up @@ -641,6 +661,81 @@ export class BulkTab extends SimTab {
});
settingsBlock.bodyElement.appendChild(clearButton);

// Talents to sim
const talentsToSimDiv = document.createElement("div")
if (this.simTalents) {
talentsToSimDiv.style.display = "flex";
} else {
talentsToSimDiv.style.display = "none";
}
talentsToSimDiv.classList.add("talents-picker-container")
const talentsLabel = document.createElement("label")
talentsLabel.innerText = "Pick talents to sim (will increase time to sim)";
talentsToSimDiv.appendChild(talentsLabel);
const talentsContainerDiv = document.createElement("div");
talentsContainerDiv.classList.add("talents-container");

const dataStr = window.localStorage.getItem(this.simUI.getSavedTalentsStorageKey());

let jsonData;
try {
if (dataStr !== null) {
jsonData = JSON.parse(dataStr);
}
} catch (e) {
console.warn('Invalid json for local storage value: ' + dataStr);
}
const handleToggle = (frag: HTMLElement, load: TalentLoadout) => {
let chipDiv = frag.querySelector('.saved-data-set-chip');
let exists = this.savedTalents.some(talent => talent.name === load.name); // Replace 'id' with your unique identifier

console.log('Exists:', exists);
console.log('Load Object:', load);
console.log('Saved Talents Before Update:', this.savedTalents);

if (exists) {
// If the object exists, find its index and remove it
let indexToRemove = this.savedTalents.findIndex(talent => talent.name === load.name);
this.savedTalents.splice(indexToRemove, 1);
chipDiv?.classList.remove('active');
} else {
// If the object does not exist, add it
this.savedTalents.push(load);
chipDiv?.classList.add('active');
}

console.log('Updated savedTalents:', this.savedTalents);
}
for (let name in jsonData) {
try {
console.log(name, jsonData[name]);
let savedTalentLoadout = SavedTalents.fromJson(jsonData[name]);
var loadout = { talentsString: savedTalentLoadout.talentsString, glyphs: savedTalentLoadout.glyphs, name: name };

let index = this.savedTalents.findIndex(talent => JSON.stringify(talent) === JSON.stringify(loadout));
const talentFragment = document.createElement('fragment');
talentFragment.innerHTML = `
<div class="saved-data-set-chip badge rounded-pill ${index !== -1 ? 'active' : ''}">
<a href="javascript:void(0)" class="saved-data-set-name" role="button">${name}</a>
</div>`;

console.log("Adding event for loadout", loadout);
// Wrap the event listener addition in an IIFE
(function (talentFragment, loadout) {
talentFragment.addEventListener("click", () => handleToggle(talentFragment, loadout));
})(talentFragment, loadout);

talentsContainerDiv.appendChild(talentFragment);
} catch (e) {
console.log(e);
console.warn('Failed parsing saved data: ' + jsonData[name]);
}
}

talentsToSimDiv.append(talentsContainerDiv);
//////////////////////
////////////////////////////////////

// Default Gem Options
const defaultGemDiv = document.createElement("div");
if (this.autoGem) {
Expand Down Expand Up @@ -740,7 +835,23 @@ export class BulkTab extends SimTab {
}
});

new BooleanPicker<BulkTab>(settingsBlock.bodyElement, this, {
label: "Sim Talents",
labelTooltip: "When checked bulk simulator will sim chosen talent setups. Warning, it might cause the bulk sim to run for a lot longer",
changedEvent: (obj: BulkTab) => this.itemsChangedEmitter,
getValue: (obj) => this.simTalents,
setValue: (id: EventID, obj: BulkTab, value: boolean) => {
obj.simTalents = value
if (value) {
talentsToSimDiv.style.display = "flex";
} else {
talentsToSimDiv.style.display = "none";
}
}
});

settingsBlock.bodyElement.appendChild(defaultGemDiv);
settingsBlock.bodyElement.appendChild(talentsToSimDiv);
}

private setSimProgress(progress: ProgressMetrics, iterPerSecond: number, currentRound: number, rounds: number, combinations: number) {
Expand Down
Loading

0 comments on commit 9b66dc4

Please sign in to comment.