Created
September 25, 2014 13:12
-
-
Save cmingxu/c032f41055f8e893a9d8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class DummyItemRealm < ActiveRecord::Base | |
belongs_to :dummy_item, | |
:class_name => 'DummyItem', | |
:foreign_key => 'dummy_item_id' | |
belongs_to :realm | |
after_save :create_job | |
after_save :create_broadcast_job | |
RANK_FIRST_SIZE = 100 | |
def self.lived(realm) | |
includes(:dummy_item).where(["dummy_items.enabled = 1 AND dummy_item_realms.realm_id = ? AND ((dummy_item_realms.begin_at <= ? AND dummy_item_realms.end_at >= ?) OR (dummy_item_realms.begin_at = 0 AND dummy_item_realms.end_at = 0))", | |
realm.id, Time.now.to_i, Time.now.to_i]).order("dummy_item_realms.begin_at DESC, dummy_item_realms.created_at DESC") | |
end | |
def self.update_dummy_item_switch(realm_id, status) | |
Rails.logger.info("~~~~set dummy item switch: realm:#{realm_id}, status:#{status}") | |
Rails.global_redis.set("dummy_item_#{realm_id}_switch", status) | |
end | |
def self.add_dummy_item_points(player, item_name_quantity_hash) | |
DummyItemRealm.lived(player.realm).each do |event| | |
next if event.dummy_item.leaderboard_enabled == 0 | |
item_name_quantity_hash.each_pair do |item_name, quantity| | |
di = event.dummy_item[:dummy_list].find {|d| d[:item_name] == item_name} | |
player.redis_server.zincrby(RKG.key_for_dummy_item_event_rank(event.id), di[:points] * quantity, player.id) if di | |
end | |
end | |
end | |
def as_summary_json(player) | |
{ | |
id: id, | |
begin_at: begin_at.to_i, | |
end_at: end_at.to_i, | |
title: DummyItem.i18n_key(dummy_item.name, "title"), | |
desc: DummyItem.i18n_key(dummy_item.name, "description"), | |
icon: dummy_item.icon, | |
dummy_list: dummy_item.dummy_list, | |
trade_in_list:dummy_item.trade_in_list | |
}.merge!({:dummy_item_player_info => self.get_player_info(player)}) | |
end | |
def forever_event? | |
return (self.begin_at == 0 && self.end_at == 0) | |
end | |
def trade_in(trade_in_id, player) | |
trade_in_info = dummy_item.trade_in_list.find{|t| t["id"] == trade_in_id.to_i} | |
return [false, 'dummy-item.errors.trade-in-not-exists'] if player.nil? || trade_in_info.nil? | |
job = player.chrono_jobs.to_a.find{|j| j.type == "BgJobs::DummyItems" && j.args["event_id"] == self.id && j.args["trade_in_id"] == trade_in_id} | |
return [false, 'dummy-item.errors.duplicate-trade-in-job'] if job.present? | |
Doam::RedisLock.with_lock(player.cache_server_redis, "p#{player.id}:event_id#{self.id}:trade_id:#{trade_in_id}") do | |
# deduct request and free times | |
suc, err = pay_for_trade_in(trade_in_info, player) | |
return [false, err] if not suc | |
if trade_in_info["duration"] > 0 | |
target_item = trade_in_info["target_items"].first || {} | |
# create job | |
BgJobs::DummyItems.create!({:realm_id => player.realm_id, :player_id => player.id, :args => {:event_id => self.id, :trade_in_id => trade_in_id, :name => target_item["name"].to_s, :type => target_item["type"].to_s}}) | |
else | |
self.claim_trade_in(trade_in_info, player) | |
end | |
# dummy item trade in logs | |
LogDb.connection.execute "INSERT INTO dummy_item_trade_in_logs(user_id, player_id, realm_id, event_id, trade_in_id, created_at) VALUES(#{player.user_id}, #{player.id}, #{player.realm_id}, #{self.id}, #{trade_in_id}, '#{Time.now.utc.to_s(:db)}')" | |
return true, nil | |
end | |
end | |
def pay_for_trade_in(trade_in_info, player) | |
# check request items | |
deduct_lua = <<LUA | |
LUA | |
lua = <<LUA | |
LUA | |
@rubies = 0 | |
trade_in_info["request_items"].each do |req| | |
@name, @amount = req["name"], req["amount"].to_i | |
case req["type"] | |
when "ruby" | |
return [false, 'dummy-item.errors.request-not-meet'] if player.user.rubies < @amount | |
@rubies += @amount | |
next | |
when "item" | |
@hash_key = player.items.key | |
PlayerUsedItem.create(:player => player, :item_name => @name , :quantity => @amount.to_i ) | |
when "resource" | |
player.capital.touch(@name.to_s.downcase) | |
@name = "last_" + @name.to_s.downcase | |
@hash_key = player.capital.resource_hash.key | |
when "troop" | |
@hash_key = player.capital.unit_hash.key | |
else | |
next | |
end | |
lua += <<LUA | |
if not redis.call("hget", "#{@hash_key}", "#{@name}") or tonumber(redis.call("hget", "#{@hash_key}", "#{@name}")) < #{@amount} then | |
return {0, 'dummy-item.errors.request-not-meet'} | |
end | |
LUA | |
deduct_lua += <<LUA | |
redis.call("hincrby", "#{@hash_key}", "#{@name}", 0 - #{@amount}) | |
LUA | |
end | |
trade_in_id, total_times = trade_in_info["id"].to_i, trade_in_info["times"].to_i | |
# check remaining trade_in times if total times config exists | |
if total_times > 0 | |
dummy_item_times_hash_key = RKG.key_for_dummy_item_times_hash(self.id, player) | |
lua += <<LUA | |
if redis.call("hsetnx", "#{dummy_item_times_hash_key}", #{trade_in_id}, #{total_times}) then | |
redis.call("expireat", "#{dummy_item_times_hash_key}", #{end_at.to_i}) | |
end | |
if tonumber(redis.call("hget", "#{dummy_item_times_hash_key}", #{trade_in_id})) <= 0 then | |
return {0, 'dummy-item.errors.remain-times-not-enough'} | |
end | |
redis.call("hincrby", "#{dummy_item_times_hash_key}", #{trade_in_id}, -1) | |
LUA | |
end | |
# deduct requests and times | |
lua += deduct_lua | |
lua += <<LUA | |
return {1, nil} | |
LUA | |
suc, err = player.redis.eval(lua, []) | |
return [false, err] if suc == 0 | |
# deduct rubies | |
if @rubies > 0 && player.user.deduct_rubies(@rubies, "DummyItem") | |
amount, sr_amount, tr_amount = player.user.deduct_shadow_rubies(@rubies, "DummyItem") | |
end | |
player.capital.update_figures | |
return true, nil | |
end | |
def claim_trade_in(trade_in_info, player) | |
lua = <<LUA | |
LUA | |
trade_in_info["target_items"].each do |tar| | |
@name, @amount = tar["name"].to_s, tar["amount"].to_i | |
flag = true | |
case tar["type"] | |
when "item" | |
flag = false | |
@hash_key = player.items.key | |
# add dummy item points | |
player.add_item(@name, @amount, "DummyItem-#{self.dummy_item.id}-#{trade_in_info['id']}") | |
when "resource" | |
player.capital.touch(@name.to_s.downcase) | |
@name = "last_" + @name.to_s.downcase | |
@hash_key = player.capital.resource_hash.key | |
when "troop" | |
@hash_key = player.capital.unit_hash.key | |
else | |
next | |
end | |
lua += <<LUA | |
if #{flag} == true then | |
redis.call("hincrby", "#{@hash_key}", "#{@name}", #{@amount}) | |
end | |
LUA | |
end | |
player.redis_server.eval(lua, []) | |
player.capital.update_figures | |
end | |
def get_player_info(player) | |
event_key = RKG.key_for_dummy_item_event_rank(self.id) | |
rank, point = nil, 0 | |
if self.dummy_item.leaderboard_enabled == 1 | |
lua = <<LUA | |
local rank = redis.call("zrevrank", "#{event_key}", #{player.id}) | |
if not rank then | |
redis.call("zadd", "#{event_key}", 0, #{player.id}) | |
rank = redis.call("zrevrank", "#{event_key}", #{player.id}) | |
end | |
local point = redis.call("zscore", "#{event_key}", #{player.id}) | |
return {rank+1, point} | |
LUA | |
rank, point = player.redis_server.eval(lua, []) | |
end | |
remain_hash = player.redis.hgetall(RKG.key_for_dummy_item_times_hash(self.id, player)) | |
if remain_hash.length < dummy_item.trade_in_list.length # initialize remain hash | |
player.redis.pipelined do | |
dummy_item.trade_in_list.each do |t| | |
if remain_hash[t["id"]].nil? | |
player.redis.hset(RKG.key_for_dummy_item_times_hash(self.id, player), t["id"], t["times"]) | |
remain_hash[t["id"]] = t["times"].to_i | |
end | |
end | |
player.redis.expireat(RKG.key_for_dummy_item_times_hash(self.id, player), self.end_at.to_i) | |
end | |
end | |
{ | |
remain_times: remain_hash, | |
rank: rank, | |
point: point | |
} | |
end | |
def create_job | |
Rails.logger.info("~~~~~#{dummy_item.enabled?}, #{new_record?}, #{updated_at_changed?}") | |
if dummy_item.enabled? && (new_record? || updated_at_changed?) | |
Rails.logger.info("~~~~~create job for dummy item realm: #{id}") | |
Resque.enqueue_at(Time.at(self.end_at).utc, Jobs::DummyItemEvent, {id: id, updated_at: updated_at.utc.to_i, realm_id: realm_id}) | |
end | |
end | |
def create_broadcast_job | |
if dummy_item.enabled? && (new_record? || updated_at_changed?) | |
Resque.enqueue_at(Time.at(self.begin_at).utc, Jobs::DummyItemEventBroadcast, {realm_id: realm_id}) | |
Resque.enqueue_at(Time.at(self.end_at).utc, Jobs::DummyItemEventBroadcast, {realm_id: realm_id}) | |
end | |
end | |
def finish_event | |
realm = Realm.find_by_id self.realm_id | |
return if realm.nil? | |
return if dummy_item.enabled == 0 || dummy_item.leaderboard_enabled == 0 | |
leaderboard = realm.redis_server.zrevrange(RKG.key_for_dummy_item_event_rank(self.id), 0, DummyItemRealm::RANK_FIRST_SIZE - 1) | |
return if leaderboard.length <= 0 | |
# send rank reward mail | |
player_list = Player.sw_to_db(realm.id).where("id IN (#{leaderboard.join(',')})").order("field (id, #{leaderboard.join(',')})").includes(:user) | |
values = "" | |
locale = (realm.locale || :en).to_sym | |
self.dummy_item.reward_list.sort{|a, b| a[:min_rank] <=> b[:min_rank]}.each do |reward| | |
i = reward[:min_rank] | |
message = MassMessage.create( | |
:subject => I18n.t("dummy-item.leaderboard.mail.subject", :locale => locale), | |
:message => I18n.t("dummy-item.leaderboard.mail.message", :locale => locale), | |
:details => {:items => reward[:items]}, | |
:realm_id => realm.id | |
) | |
while i <= reward[:max_rank] && i <= player_list.length | |
p = player_list[i-1] | |
next unless p | |
# add item | |
reward[:items].each {|item| | |
p.add_item(item.first, item.second, "dragonarena") | |
} | |
str = ActiveRecord::Base.__send__(:sanitize_sql, ["(?,?,?,?,?,?,?),", 2, Time.now.utc.to_s(:db), p.id, p.realm_id, message.id, "MassMessage", message.subject], '') unless p.nil? || message.nil? | |
values << str unless p.nil? || message.nil? | |
i = i + 1 | |
end | |
end | |
ReportNotification.connection.execute "INSERT INTO report_notifications(category, created_at, player_id, realm_id, report_id, report_type, summary) VALUES#{values[0..-2]};" | |
# clean rank set | |
realm.redis.zremrangebyrank(RKG.key_for_dummy_item_event_rank(self.id), 0, -1) | |
DummyItemRealm.update_dummy_item_switch(self.realm_id, DummyItemRealm.lived(Realm.find(realm_id)).present?) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment