Mardaneus86 / futwebapp-tampermonkey

TamperMonkey scripts to enhance the FUT 21 Web App - Discontinued
MIT License
192 stars 103 forks source link

See club / transfer list worth based on minimum BIN #17

Closed Kyderman closed 6 years ago

Kyderman commented 6 years ago

Just an idea of an enhancement of some kind, would work well in conjunction with the minimized API call to futbin.

I've been working a little bit on this but not had real time to put forward yet.

Basically, it would be very handy to see the total futbin price of the club or transfer pile so we have a better understanding of what the club is worth, but also how the market is faring (possibly use localStorage to store previous values with times / dates so comparison can be made).

Additionally, being able to sort by highest futbin price would be a great addition.

Mardaneus86 commented 6 years ago

That sounds like a very good feature to add. Feel free to share any source code you already have so we can expand on that.

Kyderman commented 6 years ago

@Mardaneus86 its very crappy and not achieving much atm, ill get something out when possible.

Mardaneus86 commented 6 years ago

Made an initial version for the club worth. When you navigate to the club overview it shows club value on the top right.

Rest of the feature requests are not handled (yet):

Kyderman commented 6 years ago

@Mardaneus86 The club worth thing doesnt seem to be calculating correctly. I apparently have a club worth of a little over 19k although I have lots of players worth way more than that.

Glancing at the script I'm not massively sure what the problem is.

Kyderman commented 6 years ago

So doing some testing, only 91 players are being returned by the club.

91 x 200 is close to that 19000 figure with a few being worth more than the 200 BIN, so I'm assuming this is grabbing the 91 cheapest players in the club (which may be why your testing was correct (you had a small club)

Kyderman commented 6 years ago

Alright, so doing some digging, it seems like some sort of iterator needs to be called to get everything, as that collection as is, is not the "endOfList"

Kyderman commented 6 years ago

"MAX_ITEMS_REQUEST = 90" is something ive found in the code, is this changeable?

Mardaneus86 commented 6 years ago

Oh you are right, I have a small club. I will check this evening and report back. Thanks for letting me know.

Kyderman commented 6 years ago

I have tried to trigger extra searches but cant find a function to make it happen unfortunately. It loads 90, which is why you dont see another loading screen until the 3rd page of club players.

I guess a solution could be to make the bot go through all pages manually in a different tab to make a total up, would take a few minutes id imagine.

Mardaneus86 commented 6 years ago

You can use the communication delegates (communication.ClubSearchDelegate) to change search criteria without screen interaction. Do you get paging buttons when you have more than 90 players in your club? When I change the MAX_ITEMS_REQUEST constant to 10, I don't get paging.

You can't just change the MAX_ITEMS_REQUEST to 1000 for example, because that will return a 461 status code (Permission Denied). So some sort of paging will be necessary by using the count and start parameters on the SearchDelegate.

The question is how Futbin will handle that many items being requested. Probably the URL max length will be exceeded (since it is a GET request).

Kyderman commented 6 years ago

Ahh a search delegate! I tell you what would be excellent, especially as you have had a longer look at this monstrosity than I. If you could make some wiki items for common functions, we could then add info to them over time. Otherwise myself or others or indeed yourself could spend a lot of time trying to find the correct functions.

I guess the best thing to do here is use the search delegate to do the 90 at a time, for maximum efficiency? we are looking at 2000 characters or so, so 90 players should be well within that limit.

Mardaneus86 commented 6 years ago

Hm, that is a good idea to try to describe the web app architecture so everyone can benefit from that. 👍 As stated in the readme, this project is mainly for personal learning purposes, so this idea fits with that.

Also be aware that club size can easily get up to hundreds, so maybe requesting the total club value should be behind a user action (eg. clicking a specific button in the UI).

Kyderman commented 6 years ago

Yes for sure,

Have you got a quick way to call this searchDelegate? Im just trying to call it now to see if I can get the required results.

Mardaneus86 commented 6 years ago

Nope, you will need to figure out what parameters this delegate requires. What I can tell you right now on top of my head is that you should call it in this form:

var o = new communication.ClubSearchDelegate(searchcriteria, start, count);
o.addListener(communication.BaseDelegate.SUCCESS, this, function marketSearch(sender, response) {
     // handle the response
}));
o.send();

The second and third parameter are the most important.

If you set a breakpoint in the Chrome developer tools in the Sources tab in the compiled_1.js file at the line after communication.ClubSearchDelegate = function(t, i, s) { you can inspect the objects that you have to pass.

PS: you can pretty print the code by pressing the curly braces in the sources tab.

Kyderman commented 6 years ago

Yeah, im just working out what needs to be in "t" atm, nearly got it sorted.

Kyderman commented 6 years ago
var o = new communication.ClubSearchDelegate({
    type: enums.SearchType.PLAYER, 
    sort: "desc",
    playStyle: 1, 
    defId: 1, 
    position: enums.SearchType.ANY, 
    year: enums.SearchType.ANY, 
    category: enums.SearchCategory.ANY,
    level: enums.SearchLevel.ANY, 
    club: 0, league: 0, nation: 0,
    isExactSearch: false, 
    zone: enums.SearchType.ANY  }, 0, 10);
o.addListener(communication.BaseDelegate.SUCCESS, this, function marketSearch(sender, response) {
     // handle the response
});
o.send();

Thus far, erroring at lack of function t.hasValidDefId()

Mardaneus86 commented 6 years ago

Ah, create it with var t = new transferobjects.SearchCriteria();. That'll make sure the search criteria object is created properly.

I see there is need for some architectural documentation. Will work on that with priority.

Kyderman commented 6 years ago

Excellent, you are a diamond!

Kyderman commented 6 years ago

EDIT: Fixed, got this working

Kyderman commented 6 years ago
var t = new transferobjects.SearchCriteria();
var o = new communication.ClubSearchDelegate(t, 0, 250);
o.addListener(communication.BaseDelegate.SUCCESS, this, function marketSearch(sender, response) {
     console.log(response)
});
o.send();

250 is the max.

OK, so this will actually bring us back the first 250 players in the club, sorted by loans, then informs etc, then normal players. Excellent.

From here, its the following:

  1. Filter to players only
  2. filter untradeable
  3. mapIds
  4. chunk ids into manageable get string chunks for futbin
  5. profit?
Mardaneus86 commented 6 years ago

I created a Gitter IM channel to have a better way of discussing instead of polluting the issues. Please continue discussion there: https://gitter.im/futwebapp-tampermonkey

By the way; very good work 👍 Keep the count on 90, otherwise EA can figure out false requests pretty easily.

Kyderman commented 6 years ago

Good point, will leave this clearer for important breakthroughs and news :)

Kyderman commented 6 years ago

UPDATE:

I have this fully working with the first 90 players in the club, with untradeable players filtered.

I will have this feature completed this evening, atm it will run in the background, however, ill probably try get a UI button together for it

WIP:

// ==UserScript==
// @name        FUT Futbin Club Worth
// @version     0.1
// @description Determines the club worth based on current Futbin BIN prices
// @license     MIT
// @author      Tim Klingeleers
// @match       https://www.easports.com/fifa/ultimate-team/web-app/*
// @grant       GM_xmlhttpRequest
// @connect     www.futbin.com
// @namespace   https://github.com/Mardaneus86
// @updateURL   https://raw.githubusercontent.com/Mardaneus86/futwebapp-tampermonkey/master/futbin-club-worth.user.js
// @downloadURL https://raw.githubusercontent.com/Mardaneus86/futwebapp-tampermonkey/master/futbin-club-worth.user.js
// @supportURL  https://github.com/Mardaneus86/futwebapp-tampermonkey/issues
// ==/UserScript==
// ==OpenUserJS==
// @author Mardaneus86
// ==/OpenUserJS==
(function () {
    'use strict';

    gNavManager.onScreenRequest.observe(this, function(obs, event) {
        if(event === "MyClubSearch") {
            var currentCount = 0;
            var currentTotal = 0;
            var gettingPlayerData = setInterval(function() {
                console.log('run');
                var t = new transferobjects.SearchCriteria();
                t.type = enums.SearchType.PLAYER;

                var o = new communication.ClubSearchDelegate(t, currentCount, 90);
                currentCount += 90
                o.addListener(communication.BaseDelegate.SUCCESS, this, function marketSearch(sender, response) {
                    var playerIds = Object.keys(response.itemData).map(function(key) { if(!response.itemData[key].untradeable){return response.itemData[key].resourceId;}});
                    if(response.itemData.length < 1) {
                        clearInterval(gettingPlayerData);
                    }

                    var futbinUrl = "https://www.futbin.com/18/playerPrices?player=&all_versions=" + playerIds.join(',');

                    var platform = '';
                    if (repositories.User.getCurrent().getSelectedPersona().isPlaystation) platform = "ps";
                    if (repositories.User.getCurrent().getSelectedPersona().isPC) platform = "pc";
                    if (repositories.User.getCurrent().getSelectedPersona().isXbox) platform = "xbox";
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: futbinUrl,
                        onload: function (res) {
                            var futbinData = JSON.parse(res.response);
                            var clubWorth = playerIds.map(function(key) {
                                if (futbinData[key]) {
                                    return parseInt(futbinData[key].prices[platform].LCPrice.replace(/,/g, ""));
                                } else {
                                    return parseInt(0);
                                }
                            }).reduce(function(a, b) {
                               return a + b;
                            }, 0);
                            currentTotal += clubWorth;
                            console.log(currentTotal)

                        }
                    });
                });
                o.send();

            }, 3000);
             $('.DetailView').prepend(`
<div><button class="list" style="cursor: default">
<span class="btn-text">Total Futbin Club Value:</span>
<span class="btn-subtext">${currentTotal}</span>
</div>`);
        }
    });
})();
Kyderman commented 6 years ago

So new changes have been requested, it works a lot quicker.

A little suggestion I could work on.

I think the club value would be great in the top bar alongside fifa points etc, could use a button for refreshing it?

If so, any idea on the right screen stuff to call for that (it wouldnt just be in the player page)