How do you edit all values in a map without knowing the keys? - minecraft

(context)
I'm doing more Minecraft spigot things, and my plugin idea is that enchantments strengthen over time, exponentially. I have a timer that is in the onEnable thing that runs a function every 2 1/2 minutes.
The function currently does:
Get a list of players,
Get inventory of those players,
Get all items of those inventories,
Get the enchantment maps for each of the items.
The problem is, I don't know every enchantment's code name(plus it would be very tedious to list every single one out), therefore I can't test every key(enchant name) to get the values(the enchantment strength). I want to just edit all of the values and set them to ceil(lvl1.2)* so I can get the strengthened enchantments to apply to the items, then apply those items to those inventories, then inventories to players.
TL;DR
How to you edit every value of a map given that you don't know the keys?

You can use Map's entrySet() method to iterate through each enchantment/level.
for (Map.Entry<Enchantment, Integer> entry : enchantmentMap.entrySet()) {
Enchantment enchantment = entry.getKey();
int level = entry.getValue();
}

Related

Firebase concurrency of reading and writing

I've got the problem when two people at the same time tries to add each other to friends. So, at first when one person presses add to friends he checks, whether other user's groups doesn't have my ID. If he has, I don't need to create new group - I will just add this group's ID to my list, else - I will create new group. Now, when two people at the same time press that button, they both get the result that group doesn't exist thus they both create a new group. How to solve these kind of problems?
Structure:
"userGroups" : {
"myId1" : {
"generatedGroupId1" : "myFriendID1"
}
}
Update: I've managed to do it: basically in doTransaction I create group if it doesn't exist and then on onComplete I work with already created group. If two people start creating new group, one end up creating it, second one - reading it.
// function
ref.runTransaction(object : Transaction.Handler {
override fun doTransaction(currentData: MutableData): Transaction.Result {
// create group here if data is null
return Transaction.success(currentData)
}
override fun onComplete(
error: DatabaseError?,
committed: Boolean,
currentData: DataSnapshot?
) {
Log.d(TAG, "postTransaction:onComplete:" + error)
// continue doing stuff, group already exists at this point
}
})
}
It's hard to give specific without seeing your code, but the most likely options are (in order of my personal preference):
Base the group ID on the two users in it. If you do this correct, the two users will end up with the same group ID, and it doesn't matter who is first. Creating the groups then becomes a so-called idempotent operation, which means that if you run the same operation multiple times, it will have the same result. For an example of such group IDs, see Best way to manage Chat channels in Firebase
Use a transaction to ensure only one write makes it through. This would mean that the second user ends up reading the group created by the first user, and can then cancel their data creation.
Use a Cloud Function, which can perform more (non-atomic) read operations to check whether the group of users already exists, and reject the request from the second user.

How to insert an item into a sequence using Sequelize, or How to manage an ordering attribute

I have an entity with a sequence attribute, which is an integer from 1-N for N members of the list. They are polyline points.
I want to be able to insert into the list at a given sequence point, and increment all the items at that point or beyond in the sequence to make room for the new item, and likewise if I delete then decrement everything above so we still have nice sequence ordering with no missing numbers.
There is a REST interface in this of course, but I dont want to hack about with that, I just want sequelize to magically manage this sequence number.
I am assuming I need to get hold of some "before insert" and "after delete" hooks in sequelize and issue some SQL to make this happen. Is that assumption correct or is there some cooler way of doing it.
I havent tested this, but this appears to be the solution, which is barely worth comment.
I know the modelName, and name==the attribute name,
options.hooks={
beforeInsert: function(record, options) {
return self.models[modelName].incrementAfter(name,record[name]);
},
afterDelete: function(record, options) {
return self.models[modelName].decrementAfter(name,record[name]);
}
}
and then added to my extended model prototype I have
incrementAfter:function(field,position){
return this.sequelize.query("UPDATE "+this.tableName+" SET "+field+" = "+field+"+1 WHERE "+field +" >= "+position);
},
decrementAfter:function(field,position){
return this.sequelize.query("UPDATE "+this.tableName+" SET "+field+" = "+field+"-1 WHERE "+field +" >= "+position);
},

EF: How to do effective lazy-loading (not 1+N selects)?

Starting with a List of entities and needing all dependent entities through an association, is there a way to use the corresponding navigation-propertiy to load all child-entities with one db-round-trip? Ie. generate a single WHERE fkId IN (...) statement via navigation property?
More details
I've found these ways to load the children:
Keep the set of parent-entities as IQueriable<T>
Not good since the db will have to find the main set every time and join to get the requested data.
Put the parent-objects into an array or list, then get related data through navigation properties.
var children = parentArray.Select(p => p.Children).Distinct()
This is slow since it will generate a select for every main-entity.
Creates duplicate objects since each set of children is created independetly.
Put the foreign keys from the main entities into an array then filter the entire dependent-ObjectSet
var foreignKeyIds = parentArray.Select(p => p.Id).ToArray();
var children = Children.Where(d => foreignKeyIds.Contains(d.Id))
Linq then generates the desired "WHERE foreignKeyId IN (...)"-clause.
This is fast but only possible for 1:*-relations since linking-tables are mapped away.
Removes the readablity advantage of EF by using Ids after all
The navigation-properties of type EntityCollection<T> are not populated
Eager loading though the .Include()-methods, included for completeness (asking for lazy-loading)
Alledgedly joins everything included together and returns one giant flat result.
Have to decide up front which data to use
It there some way to get the simplicity of 2 with the performance of 3?
You could attach the parent object to your context and get the children when needed.
foreach (T parent in parents) {
_context.Attach(parent);
}
var children = parents.Select(p => p.Children);
Edit: for attaching multiple, just iterate.
I think finding a good answer is not possible or at least not worth the trouble. Instead a micro ORM like Dapper give the big benefit of removing the need to map between sql-columns and object-properties and does it without the need to create a model first. Also one simply writes the desired sql instead of understanding what linq to write to have it generated. IQueryable<T> will be missed though.

Rails3: Cascading Select Writer's Block

I have a big, flat table:
id
product_id
attribute1
attribute2
attribute3
attribute4
Here is how I want users to get to products:
See a list of unique values for attribute1.
Clicking one of those gets you a list of unique values for attribute2.
Clicking one of those gets you a list of unique values for attribute3.
Clicking one of those gets you a list of unique values for attribute4.
Clicking one of those shows you the relevant products.
I have been coding Rails for about 4 years now. I just can't unthink my current approach to this problem.
I have major writer's block. Seems like such an easy problem. But I either code it with 4 different "step" methods in my controller, or I try to write one "search" method that attempts to divine the last level you selected, and all the previous values that you selected.
Both are major YUCK and I keep deleting my work.
What is the most elegant way to do this?
Here is a solution that may be an option. Just off the top of my head and not tested (so there is probably a bit more elegant solution). You could use chained scopes in your model:
class Product < ActiveRecord::Base
scope :with_capacity, lambda { |*args| args.first.nil? ? nil : where(:capacity=>args.first) }
scope :with_weight, lambda { |*args| args.first.nil? ? nil : where(:weight=>args.first) }
scope :with_color, lambda { |*args| args.first.nil? ? nil : where(:color=>args.first) }
scope :with_manufacturer, lambda { |*args| args.first.nil? ? nil : where(:manufacturer=>args.first) }
self.available_attributes(products,attribute)
products.collect{|product| product.send(attribute)}.uniq
end
end
The code above will give you a scope for each attribute. If you pass a parameter to the scope, then it will give you the products with that attribute value. If the argument is nil, then the scope will return the full set (I think ;-). You could keep track of the attributes they are drilling down in in the session with 2 variables (page_attribute and page_attribute_value) in your controller. Then you call the entire chain to get your list of products (if you want to use them on the page). Next you can get the attribute values by passing in the set of products and the attribute name to Product.available_attributes. Note that this method (Product.available_attributes) is a total hack and would be inefficient for a large set of data, so you may want to make this another scope and use :select=>"DISTINCT(your_attribute)" or something more database efficient instead of iterating thru the full set of products as I did in the hack method.
class ProductsController < ApplicationController
def show
session[params[:page_attribute].to_sym] = params[:page_attribute_value]
#products = Product.all.with_capacity(session[:capacity]).with_weight(session[:weight]).with_color(session[:color]).with_manufacturer(session[:manufacturer])
#attr_values = Product.available_attributes(#products,params[:page_attribute])
end
end
Again, I want to warn you that I did not test this code, so its totally possible that some of the syntax is incorrect, but hopefully this will give you a starting point. Holla if you have any questions about my (psuedo) code.

NHibernate criteria query question

I have 3 related objects (Entry, GamePlay, Prize) and I'm trying to find the best way to query them for what I need using NHibernate. When a request comes in, I need to query the Entries table for a matching entry and, if found, get a) the latest game play along with the first game play that has a prize attached. Prize is a child of GamePlay and each Entry object has a GamePlays property (IList).
Currently, I'm working on a method that pulls the matching Entry and eagerly loads all game plays and associated prizes, but it seems wasteful to load all game plays just to find the latest one and any that contain a prize.
Right now, my query looks like this:
var entry = session.CreateCriteria<Entry>()
.Add(Restrictions.Eq("Phone", phone))
.AddOrder(Order.Desc("Created"))
.SetFetchMode("GamePlays", FetchMode.Join)
.SetMaxResults(1).UniqueResult<Entry>();
Two problems with this:
It loads all game plays up front. With 365 days of data, this could easily balloon to 300k of data per query.
It doesn't eagerly load the Prize child property for each game. Therefore, my code that loops through the GamePlays list looking for a non-null Prize must make a call to load each Prize property I check.
I'm not an nhibernate expert, but I know there has to be a better way to do this. Ideally, I'd like to do the following (pseudocode):
entry = findEntry(phoneNumber)
lastPlay = getLatestGamePlay(Entry)
firstWinningPlay = getFirstWinningGamePlay(Entry)
The end result of course is that I have the entry details, the latest game play, and the first winning game play. The catch is that I want to do this in as few database calls as possible, otherwise I'd just execute 3 separate queries.
The object definitions look like:
public class Entry
{
public Guid Id {get;set;}
public string Phone {get;set;}
public IList<GamePlay> GamePlays {get;set;}
// ... other properties
}
public class GamePlay
{
public Guid Id {get;set;}
public Entry Entry {get;set;}
public Prize Prize {get;set;}
// ... other properties
}
public class Prize
{
public Guid Id {get;set;}
// ... other properties
}
The proper NHibernate mappings are in place, so I just need help figuring out how to set up the criteria query (not looking for HQL, don't use it).
since you are doing this in each request maybe it should be better to set up two formula-properties in your entity.
The first one should fetch the latest Gameplay-Id and the other the first Gameplay-Id with a not Null property
this could be as such in the xml mapping file of Entry
<property name="LatestGameplay" formula="select top(1)gp.Id from Gameplay gp where gp.FK_EntryId = PK_EntryId order by gp.InsertDate desc" />
this leaves you with the Gameplay Id's on the Entry entity and after you fetch it it would require another round trip to the DB to GetById-fetch the gameplay's
Alternatively you could work-around using filters.
Set the collection back to "lazy"
and create these nice filters
Gameplay latest = NHibernateSession.CreateFilter(entry.GamePlays , "order by InsertDate desc").SetMaxResults(1).SetFirstResult(1).UniqueResult<Gameplay>();
Gameplay winner = NHibernateSession.CreateFilter(entry.GamePlays , "where FK_PrizeId is not null order by InsertDate asc ").SetMaxResults(1).SetFirstResult(1).UniqueResult<Gameplay>();
And IFilters can be used in a multiquery as so have 2 db hits: one for the original Entry and one for the multiquery.
Last but not least, you could define 2 bags in the Entry entity, one IList<GamePlay> Latest and one IList<Gameplay> Winner which in the Entry mapping file would be filtered with the appropriate query (although i don't remember now if you can define TOP clauses in the filters) and set those as non-lazy. Then with a single round-trip you can have all the data you want with the following (ugly) syntax
Entry entry = findEntry(phoneNumber);
Gameplay winner = entry.Winner[0]; //check this if null first
Gameplay Latest = entry.Latest[0]; //ditto
note that of all the solutions the 3rd is the one that provides a mechanism to generate additional queries, as the bag can be used in a Criteria/HQL query