Dev Blog #6 - Refunds, Replacements and Corrections. The secret life of ItemIDs.
You may have noticed we've had to take the servers down for a bit, run some magic, then go back up.
This can take hours, as we saw with the Accessories and Suit Price Changes, or it can take minutes, as we saw with today's maintenance.
But the question is, what are we doing, why is the time so variable, and how does it relate to the Bind Generator?
This, is the secret life of ItemIDs.
What are Item IDs?
It's simple, item IDs (technically know as "unique IDs") are a way for the gamemode to say which item is which.
Why not just use names? Names can overlap (Think how both the Undercover and Civilian Dodge Charger have the same name), names can have spaces, names can be super long and hard to type.
Item IDs, on the other hand, are fairly short, simple, have no spaces, and are to the point.
For example, Closed Suit 'Charles Bishop' with Overcoat? That's a long name. It's ID? trenchcoat_08. Nice and simple.
It's used by the inventory command, the item use functions, the F1 menu. It's how the game talks about items.
That's why generated commands from the keybind generator use those IDs.
So, now we know what they are and why they're important, what are the issues?
Well, there's one big issue. They're really hard to change.
You make a mistake, and set a Burger to have the Unique ID "Bruger"? Unless you catch it before it goes live, you've not got a chance.
The moment someone buys a burger and has it in their inventory, it's saved in the database, you can't just rename it.
You could issue refunds, but that means turning the servers off, and going through each person's items.
You could make a new item, and quietly turn off the old one, but then people lose stuff.
Or, you could make a new item, and set the old one to be replaced by the new one. When people join, the game quietly turns the old item into the new one. But people don't always join, so that old ID is still there.
And, if you want a new item, that ID can't be used, as people still have it. It's difficult.
Combine this with the fact that some functions are case insensitive (an issue that caused the market to not show a type of ammo).
Well, it's all pretty yikes. Lots of small issues that combine into bigger ones.
Corrections
So, how do we do corrections? Glad you asked.
It's pretty easy, let's grab the code that defines a hat.
BASE:Clone()
:SetName("Grey Cs Baseball Hat")
:SetSkin(2, true)
:Register("baseballhat2_3")
ITEM:Replacement("baseballhat2_3", "baseballhat07_3")
BASE is the baseball cap item, which has the stuff that's the same. The model, the description, the price.
ITEM is a table which has all our functions in it.
So, part 1, we make the real item. baseballhat2_3 is a real item that works.
Then, ITEM:Replacement() clones that item, making an identical copy (same price, same description).
It marks it as replaced by the real item, makes it unbuyable and makes it so using it gives you the real item (back in the day, it wouldn't auto-replace, so that's so people could get the new item))
Finally, it takes that copy, and says to the game "this is the old item".
Two items, one old, one new, and when people log in, it replaces.
Pretty cool.
But, that only works when people connect. If people have old items and don't join for a while, they keep them. We'll solve that later.
Replacements
Honestly, this is the same as corrections, but we use a different item. (Also the example uses older item definitions, but it does the same thing.)
local ITEM = {}
ITEM.name = "Toyota Supra"
ITEM.cost = 190000
ITEM.model = "models/supra.mdl"
ITEM.plural = "Toyota Supra"
ITEM.uniqueID = "supra"
ITEM.description = "A tuned car with a fast nitro gas system. This item is 0 big"
ITEM.vehiclelist = "Supra"
ITEM.category = "Vehicles"
ITEM.replaced = true
ITEM.replacedid = "corvette_c7_stingray_2014"
cityrp.item.register(ITEM, "base_vehicle")
Refunds
Uh, refunds. Well.
Three ways.
Set item.outdated (I think it's outdated anyway), then that adds the sell button for a full refund.
We take the server down, find anyone with the item, and give them money.
Or, we create a "refund cheque" item, that's worth however much, and use the replacement technique to give everyone cheques (useful if there's multiple items).
#1 and #3 have the same issues, they're manual.
#2 can take a long time. But, we have a tool for it.
The Mass Refund Service.
In a secure section of the website, is the mass refund service.
It runs a script in PHP, gets every player, their inventory, scans through, checks against a list, and issues refunds.
But, it's running on a website, with limited resources, and makes a huge webpage. It's slow, and last time I used it, it crashed my Chrome.
Two hours of downtime, and no way of checking what actually happened? That's not good enough.
The Mass Refund Tool.
So, instead of that, I wrote another PHP tool.
A CLI tool, thats quick and versatile, and does a bunch more stuff than just refunds.
You want a list of all items on beta, where less than 30 are owned, but have a total value of more than $100k?
Boom, there it is.
Now, when I say quick, how quick?
To give you an idea, the service took 2 hours for the last set of DB changes we ran. The tool did it in 10 minutes.
But, more than that, the service was very simple. It took a list of IDs and a money amount, and would take any of those IDs and give money back.
It worked, but only really for refunds.
What can the new one do? It can, refund items to money, convert items to other items, convert items to multiple items, or do combinations of all of that.
People had an old car, and you want to give them a new model? Easy.
{
"ferrari": "spider",
"mclaren_p1": "mclaren_2014_p1",
"mustang": "1970_ford_mustang_boss_429",
"volvo": "volvos60"
}
Want to refund anyone who had charged taser cell schematics?
{
"sch_charged_cell": 30000
}
You want to give anyone who had a GMC Savana News Van 5k and a regular GMC Savana? Not a problem.
{
"gmcsavana_news": {
"money": 5000,
"gmcsavana": 1
}
}
Now, what else is nice. Imagine you wanted to refund everyone who had a GMC Savana.
You could run both the refunds for the News van first, then a refund for the Savana, but the tool handles that for you.
{
"gmcsavana_news": {
"money": 5000,
"gmcsavana": 1
},
"gmcsavana": 60000
}
Anyone who had a Savana gets 60k, anyone who had a Savana News gets 65k.
So, what did we do this morning?
Well, I went over the list of replaced items, more than 100 of them, and set the refund tool to process them.
And it took 5 minutes.
Specifically, we:
- Fixed some non-existent beanies.
- Removed accessories which never existed.
- Replaced the BMW GTR with the Nissan GTR.
- Replaced the old Ferrari, Volvo, P1, Kamaz, Mustang, Police Charger, Tow Truck with their current IDs.
- Replaced all the old fire engines with the current one.
- Fixed the old GMC Savanah.
- Replaced the old GMC Savanah News with the GMC Savana & a 5k refund (as the News van was more expensive).
- Replaced the old Secret Service Suburban and Fire Suburban.
- Replaced the 3 old sign IDs with the current one.
- Removed a bunch of beta items.
- Replaced the HL2 axe with the woodcutters axe.
- Merged Quad Mag / BetaC Mods, both are replaced by the extended mag kit.
- Fixed there being like 3 versions of each ammotype.
- Replaced all goldfish with salmon, all fish with rotten food.
- Fixed the Burger unique ID.
- Replaced the old fishing rod with the new one.
- Changed the turkey dinner unique ID (as it was still christmas dinner).
- Old Gov/Police caps.
- Some really really old suits.
- Processed fully the response clothing, dodge monaco police, pepper spray, package, christmas cracker, 5.45x39mm and charged cell refunds.
Then, deleted all the replacements / old items.
Saving DB space, as we don't have items in inventories that can't be used.
Saving game code space, as we don't have items there.
Freeing up new IDs if we ever need them.
And finally, letting people use items that were stored in their inventory.
So finally.
Hopefully this has been insightful, if a bit rambly, on item IDs, our refund tools, item files and more.
I hope y'all have a good day.