[XP] Versioning for RMX-OS

Started by Blizzard, May 30, 2010, 04:42:57 am

Previous topic - Next topic

Wizered67

February 20, 2011, 02:11:55 pm #80 Last Edit: February 20, 2011, 02:21:56 pm by Wizered67
Good idea. I'll try it and hopefully it will help.
edit: I tried not adding graphics and audio, but I still get the same error. The Game.rgssad size is 1.49 MB. I'm not sure if this is too big. Also, if it makes a difference, the client error was actually server did not respons, not the disconnection.

Blizzard

I have had a problem with transfer of large files earlier, but I solved that problem a long time ago. I have no problem transferring a file of 60 MB. :/
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Wizered67

That's weird.....I'll check if I'm doing soemthing wrong.

Vaelen

Hi short question. I can update in my Lan without any problems. Now a friend tested it (normaly we work with svn) and he can't update. Always a error with Server did not respond. Normal connection works fine.

maybe you know the problem.. or do I need a other port forwarded?
thx blizz for the great work (I don't have to do) ;)
RMX-OS gonna be legen.... wait-for-it... www.youtube.com/watch?v=Dqf1BmN4Dag

Blizzard

Did you install both client plugin and server extension properly? Is the plugin below the RMX-OS script? Does the RMX-OS server tell you that it has successfully loaded the server extension?
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Vaelen

The Plugin is below the RMX-OS script and above the main.
The Extension is loaded and like i said it works fine for me.. but not for my friends.
I tried it in a virtual box and it works fine too.. so I don't have any idea why it doesn't work outsite..

One thing is, I can only connect through local ip adresses (192.168..) or over loopback (127..)  if I try to connect over my outside IP (wich is shown as online) I can't connect, my friends can. But I think that behaviour is normal. But with this I can reconstruct the error message. .. but that doesn't help very much why every one can connect to my server but the update don't work..
thx blizz for the great work (I don't have to do) ;)
RMX-OS gonna be legen.... wait-for-it... www.youtube.com/watch?v=Dqf1BmN4Dag

Blizzard

Well, the only thing that's left is that you should check once more time if the proper port has been forwarded. :/
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

Vaelen

54629 in the settings of the server and port forwarded.. .. hmm  ok maybe its his firewall or UAC..  I will try with several other friends.. maybe it will work someday on a root server
thx blizz for the great work (I don't have to do) ;)
RMX-OS gonna be legen.... wait-for-it... www.youtube.com/watch?v=Dqf1BmN4Dag

mroedesigns

July 18, 2011, 02:53:45 am #88 Last Edit: July 18, 2011, 02:55:55 am by mroedesigns
Having a problem getting this to update correctly. It recognizes it needs an update, but disconnects when it tries. I'm updating game.exe, so that might be why, but it's also throwing an error saying the directory doesn't exist when it does. The 'Version' folder is in the RMX-OS Server folder, and I changed the path in the extension to Version from Extensions.

Spoiler: ShowHide


and here's what 2.txt says, located in the Version folder.
:file
   Version/2/Game.exe
   Game.exe

G_G

The client itself is trying to open "/Version/2/Game.exe" thats clear. Maybe it has something to do with trying to overwrite Game.exe, which it can't since Game.exe is the one processing everything and since its open, it very well can't be replaced can it?

mroedesigns

Well I tried it with Version/2/Data/Scripts.rxdata and it's giving me the same error. Client side it tries to update, says is updating, and then says you've been disconnected from the server. And the server is showing the same error as below.

I'm thinking I've got the relative directory wrong? It was just 'Extensions' so I changed it to 'Version' and put everything in that folder (2.txt and the folder '2' (with 2/Data/Scripts.rxdata)

Blizzard

It should be working like that. O_o
Try removing "Version/" after ":file". I don't think it will work, but try it anyway.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

mroedesigns

Nope, it's giving me the same error. It's trying the directory as just '2/Data/Scripts.rxdata' so I wonder if that has something to do with it? Is it not pointing to the Version folder correctly perhaps?

A client at 2011-07-18 08:55:10 UTC has caused an error:
No such file or directory - 2/Data/Scripts.rxdata

Blizzard

Are you sure that you have configured the extension right? I set the VERSION_LOG_PATH to "Version" and it worked just fine when I put everything into the Version folder.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

mroedesigns

Spoiler: ShowHide
module RMXOS
 
  def self.load_current_extension
    return Versioning
  end
 
end

#======================================================================
# module Versioning
#======================================================================

module Versioning

  VERSION = 1.1
  RMXOS_VERSION = 1.15
  SERVER_THREAD = false
 
  # START Configuration
  GAME_VERSION = 1 # game version
  VERSION_LOG_PATH = 'Version' # where are the version log files located
  CHUNK_MAX_SIZE = 5000 # maximum number of bytes transferred at once
  # END Configuration
 
  def self.initialize
  end
 
  def self.main
    while RMXOS.server.running
      self.server_update
      sleep(0.1)
    end
  end
 
  def self.server_update
  end
 
  def self.client_update(client)
    case client.message
    when /\ACON(.+)\t(.+)/ # connection request
      version = $1.to_i
      if version < GAME_VERSION
        client.send('VNO')
        return true
      end
      client.message = "CON#{$2}"
    when /\AUPD(.+)/ # update request
      version = $1.to_i
      while version < GAME_VERSION
        version += 1
        file = File.open("#{VERSION_LOG_PATH}/#{version}.txt", 'r')
        lines = file.readlines
        file.close
        lines.each {|line|
          line.gsub!("\r") {''}
          line.gsub!("\n") {''}}
        self.parse_version(client, lines)
        client.send('UEX')
      end
      client.send('UEN')
      return true
    end
    return false
  end
 
  def self.parse_version(client, lines)
    command = ''
    while lines.size > 0
      current = lines.shift
      next if current.size == 0
      if current[0, 1] == ':'
        command = current
      else
        case command
        when ':file'
          self.send_file(client, current, lines.shift)
        when ':dir'
          self.send_dir(client, current, lines.shift)
        when ':delete'
          client.send("DEL#{current}")
        end
      end
    end
  end
 
  def self.send_file(client, source, destination)
    file = File.open(source, 'rb')
    data = file.read
    file.close
    if data.size <= CHUNK_MAX_SIZE
      rawdata = data.inspect
      client.send("FIL#{destination}\t#{rawdata}")
    else
      client.send("FIL#{destination}\t")
      while data.size > CHUNK_MAX_SIZE
        current = data[0, CHUNK_MAX_SIZE].inspect
        data = data[CHUNK_MAX_SIZE, data.size - CHUNK_MAX_SIZE]
        client.send("APP#{destination}\t#{current}")
      end
      rawdata = data.inspect
      client.send("APP#{destination}\t#{rawdata}")
    end
  end
 
  def self.send_dir(client, source, destination)
    client.send("MKD#{destination}")
    Dir.foreach(source) {|name|
      if name != '.' && name != '..'
        filename = "#{source}/#{name}"
        if FileTest.directory?(filename)
          self.send_dir(client, filename, "#{destination}/#{name}")
        elsif FileTest.file?(filename)
          self.send_file(client, filename, "#{destination}/#{name}")
        end
      end
    }
  end
 
end


named Updater.rb and i know its in the config extensions right because the server starts and loads all the extensions correctly [right now only blizz-abs and this since im testing compatibility]

G_G

*adds to "Blizzards will eventually look at" list* :V

mroedesigns

Hopefully sooner rather than later haha

Blizzard

Lol! As I said, it works for me. :/
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

mroedesigns

July 18, 2011, 05:23:57 pm #98 Last Edit: July 18, 2011, 05:43:49 pm by mroedesigns
Well it doesn't work for me :/ ill post the script as well since the extensions already posted..

Spoiler: ShowHide
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
# Versioning for RMX-OS by Blizzard
# Version: 1.1
# Type: RMX-OS Add-on
# Date: 30.5.2010
# Date v1.01: 12.9.2010
# Date v1.1: 17.9.2010
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#
#  This script is to be distributed under the same terms and conditions like
#  the script it was created for: RMX-OS.
#
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=
#
# Information:
#
#   This script must be placed below RMX-OS and requires RMX-OS v1.15 or
#   higher to work properly. It is able to update the game client connecting
#   to the server to the newest game version.
#  
#  
# Instructions:
#  
#   The server extension validates the game version from the client and if the
#   client game version is lower than the server game version, the server will
#   refuse a connection. Instead the server will notify the client that it is
#   possible to update. After the player has confirmed that he wants to update
#   the client, the server will initiate version updating of the server. For
#   the server to know which files need to be sent, you need to create version
#   log files.
#  
#  
# Version Logs:
#  
#   The version log files on the server have a simple format. Each file is
#   named like "NUMBER.txt" where NUMBER is the version.
#  
#   examples:
#    
#     10.txt - version log for updating from version 9 to 10
#     15.txt - version log for updating from version 14 to 15
#     5475685.txt - version log for updating from version 5475684 to 5475685
#    
#   Version log files have a specific format that allows you to define which
#   files need to be updated. The basic format is:
#    
#     :COMMAND
#     FILES
#  
#   The following commands are at your disposal:
#    
#     file - update a single file
#     dir - update an entire directory with all subdirectories recursively
#     delete - delete a file OR a directory with all subdirectories recursively
#  
#   When using the ":delete" command, the FILES parameter is the name of the
#   file or directory that is affected.
#   When using the ":file" or the ":dir" command, there are 2 FILES parameters.
#   The first is the source file path and the second the destination file path.
#   You can add many files as you want with one single command.
#  
#   example:
#    
#     :file
#     versions/24/Game.rgssad
#     Game.rgssad
#     versions/Fonts.zip
#     fonts/fonts.dat
#     :dir
#     versions/24/BGM
#     Audio/BGM
#     :delete
#     utils/screenshot.dll
#     game.ico
#     artwork
#     :dir
#     versions/24/Audio/ME
#     Audio/ME
#    
#   The example above will do following:
#    
#     1. The file "versions/24/Game.rgssad" from the RMX-OS root directory will
#        be transferred to the client and store in the file "Game.rgssad" in
#        his game's root directory.
#     2. The file "versions/Fonts.zip" from the RMX-OS root directory will be
#        transferred to the client and stored in the file "fonts/fonts.dat" in
#        his game's root directory.
#     3. The directory "versions/24/BGM" and all of its contents (recursively)
#        from the RMX-OS root directory will be transferred to the client and
#        store in the directory "Audio/BGM" in his game's root directory.
#     4. The file or directory "utils/screenshot.dll" will be deleted.
#     5. The file or directory "game.ico" will be deleted.
#     6. The file or directory "artwork" will be deleted.
#     7. The directory "versions/24/Audio/ME" and all of its contents
#        (recursively) from the RMX-OS root directory will be transferred to
#        the client and stored in the directory "Audio/ME" in his game's root
#        directory.
#  
#  
# Notes:
#  
#   - There is no syntax checking or other verification of your version log
#     files. It is recommended not to use batch processing with one command but
#     use a command for every single file or directory.
#    
#     example:
#    
#       Instead of this type of writing:
#      
#       :file
#       versions/24/Game.rgssad
#       Game.rgssad
#       versions/Fonts.zip
#       fonts/fonts.dat
#    
#       use this type of writing:
#      
#       :file
#       versions/24/Game.rgssad
#       Game.rgssad
#       :file
#       versions/Fonts.zip
#       fonts/fonts.dat
#      
#   - Make sure to update the client scripts each time because you need to
#     update the constant GAME_VERSION in the configuration of this script to
#     make sure the client knows it's up to date. Either update Scripts.rxdata
#     or update Game.rgssad where Scripts.rxdata is contained.
#   - Update is done only all at once. First all files are downloaded into a
#     temporary directory. After a successful download of ALL files, first the
#     files and directories that need to be delete are deleted, then the
#     downloaded files are moved into the actual game's directory and are
#     updated.
#   - Multiple version updates work one after another and are all done at once.
#     If one version update fails for some reason, the previous updates will
#     not be lost.
#   - It is recommended to keep version updates small. Big updates are more
#     likely to break. You can simply split an update into several updates if
#     it's too big.
#  
#  
# If you find any bugs, please report them here:
# http://forum.chaos-project.com
#:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=

if !defined?(RMXOS) || RMXOS::VERSION < 1.15
 raise 'ERROR: The "Versioning" requires RMX-OS 1.15 or higher.'
end

$rmxos_versioning = 1.1

#==============================================================================
# module RMXOS
#==============================================================================

module RMXOS
 
 CONNECTION_VERSION_MISMATCH = 134
 UPDATING_END                = 135
 
 #============================================================================
 # module RMXOS::Options
 #============================================================================

 module Options
 
   #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
   # START Configuration
   #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 
   GAME_VERSION = 1 # internal version number, use integers only
   EXECUTABLE = 'Game.exe' # game executable (usually Game.exe)

   #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
   # END Configuration
   #::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 
 end
 
 #============================================================================
 # module RMXOS::Data
 #============================================================================
 
 module Data
   
   AnswerNo      = 'No'
   AnswerYes     = 'Yes'
   UpdatingNow   = 'Updating now. This may take a while.'
   UpdatePrompt  = 'Your client needs to be updated. Continue?'
   UpdateRestart = 'Update finished. If the game does not restart automatically, please restart it manually.'
   
   TempDir = ENV['TEMP'].gsub('\\', '/') + '/RMXP_update' # system temp folder
   # don't change this
   TempDir += Options::GAME_VERSION.to_s
   
 end

 #============================================================================
 # RMXOS::Network
 #============================================================================

 class Network
   
   def request_connection
     self.send("CON#{RMXOS::Options::GAME_VERSION}\t#{RMXOS::VERSION}")
   end
   
   def request_update
     if FileTest.exist?(RMXOS::Data::TempDir)
       Dir.clear(RMXOS::Data::TempDir)
     else
       Dir.mkdirs(RMXOS::Data::TempDir)
     end
     @delete_queue = []
     self.send("UPD#{RMXOS::Options::GAME_VERSION}")
   end
   
   alias check_connection_versioning_later check_connection
   def check_connection(message)
     case message
     when /\AVNO\Z/ # game version mismatch
       @messages.push(CONNECTION_VERSION_MISMATCH)
       return true
     when /\AMKD(.+)/ # make directory
       Dir.mkdirs("#{RMXOS::Data::TempDir}/#{$1}")
       return true
     when /\AFIL(.+)\t\Z/ # copy empty file
       path = "#{RMXOS::Data::TempDir}/#{$1}"
       Dir.create_path(path)
       file = File.open(path, 'wb')
       file.close
     when /\AFIL(.+)\t(.+)/ # copy file
       path = "#{RMXOS::Data::TempDir}/#{$1}"
       Dir.create_path(path)
       data = eval($2)
       file = File.open(path, 'wb')
       file.write(data)
       file.close
       return true
     when /\AAPP(.+)\t(.+)/ # append to file (in case of big files)
       path = "#{RMXOS::Data::TempDir}/#{$1}"
       Dir.create_path(path)
       data = eval($2)
       file = File.open(path, 'ab')
       file.write(data)
       file.close
       return true
     when /\ADEL(.+)/ # delete directory / file
       @delete_queue.push($1)
       return true
     when /\AUEN\Z/ # updating end
       Dir.clear(RMXOS::Data::TempDir)
       Dir.rmdirs(RMXOS::Data::TempDir)
       @messages.push(UPDATING_END)
       return true
     when /\AUEX\Z/ # execute update
       @delete_queue.each {|filename|
           if FileTest.directory?(filename)
             Dir.clear(filename)
             Dir.rmdirs(filename)
           else
             File.delete(filename) rescue nil
           end
           Graphics.update}
       Dir.copy(RMXOS::Data::TempDir, '.')
       Dir.clear(RMXOS::Data::TempDir)
       @delete_queue = []
       return true
     end
     return check_connection_versioning_later(message)
   end
   
 end
 
end

#==============================================================================
# Dir
#==============================================================================

class Dir
 
 def self.clear(source)
   dirs = [source]
   while dirs.size > 0
     dir = dirs.shift
     dirs += self.clear_non_recursive(dir)
   end
 end
 
 def self.clear_non_recursive(source)
   dirs = []
   Dir.foreach(source) {|name|
       if name != '.' && name != '..'
         filename = "#{source}/#{name}"
         if FileTest.directory?(filename)
           dirs.push(filename)
         elsif FileTest.file?(filename)
           File.delete(filename) rescue nil
         end
       end}
   return dirs
 end
 
 def self.copy(source, destination)
   dirs = [[source, destination]]
   while dirs.size > 0
     dir = dirs.shift
     Dir.mkdirs(dir[1]) if !FileTest.exist?(dir[1])
     dirs += self.copy_non_recursive(dir[0], dir[1])
   end
 end
 
 def self.copy_non_recursive(source, destination)
   dirs = []
   Dir.foreach(source) {|name|
       if name != '.' && name != '..'
         filename = "#{source}/#{name}"
         target = "#{destination}/#{name}"
         if FileTest.directory?(filename)
           dirs.push([filename, target])
         elsif FileTest.file?(filename)
           File.copy(filename, target) rescue nil
         end
       end}
   return dirs
 end
 
 def self.create_path(source)
   dirs = source.split('/')
   dirs.pop
   Dir.mkdirs(dirs.join('/')) if dirs.size > 0
 end
 
 def self.mkdirs(source)
   dirs = source.split('/')
   path = dirs.shift
   loop do
     Dir.mkdir(path) rescue nil if !FileTest.exist?(path)
     break if dirs.size == 0
     path += '/' + dirs.shift
   end
 end
 
 def self.rmdirs(source)
   all_dirs = [source]
   dirs = [source]
   while dirs.size > 0
     dir = dirs.shift
     new_dirs = self.get_subdirs(dir)
     dirs += new_dirs
     all_dirs += new_dirs
   end
   all_dirs.sort.reverse.each {|dir| Dir.rmdir(dir) rescue nil}
 end
 
 def self.get_subdirs(source)
   dirs = []
   Dir.foreach(source) {|name|
       if name != '.' && name != '..'
         filename = "#{source}/#{name}"
         dirs.push(filename) if FileTest.directory?(filename)
       end}
   return dirs
 end
 
end

#==============================================================================
# File
#==============================================================================

class File

 def self.copy(source, destination)
   file = File.open(source, 'rb')
   data = file.read
   file.close
   file = File.open(destination, 'wb')
   file.write(data)
   file.close
   Graphics.update # prevent script is hanging error
 end
 
end

#==============================================================================
# Window_Dialog
#==============================================================================

class Window_Dialog < Window_Command
 
 def initialize(width, commands = ['Yes', 'No'], caption = 'Are you sure?')
   commands.push('')
   @caption = caption
   @cursor_width = 32
   super(width, commands)
   if $fontface != nil
     self.contents.font.name = $fontface
     self.contents.font.size = $fontsize
   elsif $defaultfonttype != nil
     self.contents.font.name = $defaultfonttype
     self.contents.font.size = $defaultfontsize
   end
   self.x, self.y, self.z = 320 - self.width/2, 200 - self.height/2, 1500
   @item_max, self.opacity = commands.size-1, 192
   commands.each {|c|
       w = self.contents.text_size(c).width
       @cursor_width = w if @cursor_width < w}
   @cursor_width += 32
   refresh
   update_cursor_rect
 end
 
 def refresh
   super
   self.contents.font.color = system_color
   self.contents.draw_text(4, 0, self.width-40, 32, @caption, 1)
 end
 
 def draw_item(index, color)
   self.contents.font.color = color
   rect = Rect.new(4, 32 * (index+1), self.contents.width - 8, 32)
   self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
   self.contents.draw_text(rect, @commands[index], 1)
 end
 
 def update_cursor_rect
   if @index < 0 || @item_max == 0
     self.cursor_rect.empty
   else
     x = (self.contents.width - @cursor_width) / 2
     self.cursor_rect.set(x, (@index+1)*32, @cursor_width, 32)
   end
 end
 
end

#==============================================================================
# Scene_Servers
#==============================================================================

class Scene_Servers
 
 alias update_versioning_later update
 def update
   if @dialog_window == nil
     update_versioning_later
     if @wait_count == 0 && @update_mode
       @update_mode = nil
       @help_window.set_text(@helptext)
       Dir.clear(RMXOS::Data::TempDir)
       Dir.rmdirs(RMXOS::Data::TempDir)
     end
   else
     @dialog_window.update
     if Input.trigger?(Input::B)
       $game_system.se_play($data_system.cancel_se)
       @dialog_window.dispose
       @dialog_window = nil
     elsif Input.trigger?(Input::C)
       $game_system.se_play($data_system.decision_se)
       if @dialog_window.index == 0
         @help_window.set_text(RMXOS::Data::UpdatingNow)
         @wait_count = RMXOS::Options::SERVER_TIMEOUT * 2
         $network.request_update
         @update_mode = true
       end
       @dialog_window.dispose
       @dialog_window = nil
     end
   end
 end
 
 alias waiting_for_server_versioning_later waiting_for_server
 def waiting_for_server
   waiting_for_server_versioning_later
   $network.messages.each {|message|
       case message
       when RMXOS::CONNECTION_VERSION_MISMATCH # version mismatch
         @dialog_window = Window_Dialog.new(416, [RMXOS::Data::AnswerYes,
             RMXOS::Data::AnswerNo], RMXOS::Data::UpdatePrompt)
         return false
       when RMXOS::UPDATING_END # updating done
         @update_mode = false
         p RMXOS::Data::UpdateRestart
         Thread.new {system(RMXOS::Options::EXECUTABLE)}
         exit
         return false
       end}
   return true
 end
 
end

Blizzard

As I said, I don't know why it doesn't work for you. :/ It works fine for me regardless of the absolute path. Have you checked the capitalization of the letters? "Version" is different from "version". That's the last thing I can think of. :/
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.