Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Multiple Game Instances [RESOLVED]

Hi there!,
Is there a way for RMXP to detect whether another copy of the game is running on the same machine?
My game is an Online one, and people are exploiting the PvP system by getting a dud character and sitting them
in the PvP area, killing them, and earning far too much money and exp for what its worth.

Possibly a script that can allow me to specify the executable name, so i can ban certain applications, not just multiple instances of Game.exe from running. (eg Cheat Engine)

But just multiple instances would be fine.
Any ideas would be greatly appreciated!
Thanks guys
 
Yes, there is definitely authentification, but that won't help in this matter.
Sadly, as Sweet Vengance is gone (programmer of the server I use), i don't have a server I can tinker with :\
So I have to just make do with what I have.
 
Well just check the IP. When a person logs in check if the same IP of a person is already online, if it is then deny access.

Also that gives you a great anti-hack if someone steals user data, when people can't login they will receive that message that the same IP is already logged in.

If this is implemented in authentication part then you should have NO problems. The only other way people should be able to log into your game is via a proxy, but since you're not probably allowing it to be used from within a game you should be safe.

But if you really want a one-instance script. Here:
[rgss] 
#==============================================================================
# OneInstance Script
# by Drago del Fato
# Version: 1.0.1
# License: Free for non commercial
# If you use it put me in credits.
#==============================================================================
# [ Instructions ]
# Insert above main.
# In Main Script post this:
# 1. After begin put this:  
#      $instance_test = OneInstance.new
#
# 2. After main loop put this, it should look like:
#   while $scene != nil
#    $scene.main
#  end
#  $instance_test.dispose
#
# 3. Before end put this:
# rescue SystemExit
#   $instance_test.dispose
#
#
# And you're set. You can edit the name of the token file, and the message
# which will be displayed if an user runs another instance of the game.
# Token file cannot be deleted while the game is running, and after the game
# closes token file is deleted. If people cannot run their game. Say that they,
# need to delete it before running it if in any case it stays (sudden system
# reboot, power failure or similar)
#==============================================================================
module OneInstanceConsts
  MESSAGE = "This program is already opened. Closing now."
  TOKEN_FILE = "token"
end
 
class OneInstance
 
  def initialize
     if FileTest.exists?("./" + OneInstanceConsts::TOKEN_FILE)
       print OneInstanceConsts::MESSAGE
       exit!
     end
     @fToken = File.open("./" + OneInstanceConsts::TOKEN_FILE, "w")
   end
   
   def dispose
     @fToken.close
     File.delete("./" + OneInstanceConsts::TOKEN_FILE)
   end
end
 
[/rgss]

This script creates an empty token file which is a flag that the game is open. Any new instance of the game will check if that file exists. And since it's open by the game you cannot delete it by any normal means.

Please note that this is kind of a quick way to solve a problem, one instance checking would require a bit of Win32API calls to get Process ID's, this is an easy way to fix the problem.
 
It just says it can't find the file :\
At which part of the script does it make the file?


Never mind. Fixed it.

Ahh, nope, another problem. I have buttons like the 'x' button. When u click it, it makes $scene = nil, right?
When I click it, it raises 'IO: stream closed.

Heres my Main:
Code:
#==============================================================================

# ** Netplay Main

#------------------------------------------------------------------------------

#  After defining each class, actual processing begins here.

#==============================================================================

 

begin

  $instance_test = OneInstance.new

  $footsteps = false

  Graphics.frame_rate = 100

 

=begin

if $full == nil

 $showm = Win32API.new 'user32', 'keybd_event', %w(l l l l), '' 

$showm.call(18,0,0,0) 

$showm.call(13,0,0,0) 

$showm.call(13,0,2,0) 

$showm.call(18,0,2,0) 

$full = 1

end#  Resolution.initialize

=end

 

   width = Screen_Data::Screen_Data[0].to_s.to_i

   height = Screen_Data::Screen_Data[1].to_s.to_i

   screen = Screen_Size.new

   screen.change_screen_size(width, height)

   

  Network::Main.initialize

  $game_language = Game_Language.new

  $hudskin = true

  $no_pvp = 0

  $smooth_scroll = true

  $Respawn = []

  # Font used in windows

  $defaultfonttype = $fontface = $fontname = Font.default_name = "Verdana"

  # Font size used

  $defaultfontsize = $fontsize = Font.default_size =  14

  $mouse = $Mouse = Game_Mouse.new

  $Mouse.visible

  # Sets default font settings.

  Font.default_name = "Verdana"

  Font.default_size = 18

  Font.default_color = Window_Edits::Normal_color

  Font.default_bold = false

  Font.default_italic = false

  # Change the $fontface variable to change the font style

  $fontface = "Verdana"

  # Change the $fontsize variable to change the font size

  $fontsize = 24

  # Prepare for transition

  Graphics.freeze

  # Make scene object (connect screen)

  $scene = Scene_Connect.new

  # Call main method as long as $scene is effective

  while $scene != nil

      $scene.main

    end

  $instance_test.dispose

  # Fade out

  Network::Main.close_socket 

  Graphics.transition(25)

  #exit

rescue SystemExit

    $instance_test.dispose

rescue Errno::ENOENT

  Network::Main.close_socket 

  # Supplement Errno::ENOENT exception

  # If unable to open file, display message and end

  filename = $!.message.sub("No such file or directory - ", "")

  print("Unable to find file #{filename}.")

  time = Time.now

  time = time.strftime("%a %d %b %Y, %X") 

  File.open("ErrorLog.rxdata","a+"){ |fh| fh.puts("On <<#{time}>> the file <<#{filename}>> was missing." )}

ensure

#  $window.normal

  Network::Main.close_socket if Network::Main.socket != nil

end

 

Whats the problem?
 
Hmm... here I modified it a bit.

[rgss] 
#==============================================================================
# OneInstance Script
# by Drago del Fato
# Version: 1.0.2
# License: Free for non commercial
# If you use it put me in credits.
#==============================================================================
# [ Instructions ]
# Insert above main.
# In Main Script post this:
# 1. After begin put this:  
#      $instance_test = OneInstance.new
#
# 2. After main loop put this, it should look like:
#   while $scene != nil
#    $scene.main
#  end
#  $instance_test.dispose
#
# 3. Before end put this:
# rescue SystemExit
#   $instance_test.dispose
#
#
# And you're set. You can edit the name of the token file, and the message
# which will be displayed if an user runs another instance of the game.
# Token file cannot be deleted while the game is running, and after the game
# closes token file is deleted. If people cannot run their game. Say that they,
# need to delete it before running it if in any case it stays (sudden system
# reboot, power failure or similar)
#==============================================================================
module OneInstanceConsts
  MESSAGE = "This program is already opened. Closing now."
  TOKEN_FILE = "token"
end
 
class OneInstance
 
  def initialize
     if FileTest.exists?("./" + OneInstanceConsts::TOKEN_FILE)
       print OneInstanceConsts::MESSAGE
       exit!
     end
     @fToken = File.open("./" + OneInstanceConsts::TOKEN_FILE, "w")
   end
   
   def dispose
      @fToken.close if !@fToken.closed?
     File.delete("./" + OneInstanceConsts::TOKEN_FILE) if FileTest.exists?("./" + OneInstanceConsts::TOKEN_FILE)
   end
end
 
[/rgss]

It shouldn't cause those problems now.
And since you're using ensure in that main class we can use it for this script too. Just put $instance_test.dispose there and remove:
rescue SystemExit
$instance_test.dispose

and $instance_test.dispose after:
while $scene != nil
$scene.main
end

That should definitely fix the problem if the above fix doesn't. :)
 
Oh, and 1 more thing, for others reading this thread who want to use this script (if there are any others)
This will attempt to delete the token upon startup, so if there was a power faliure or the game was closed via processes, it will still work.
Here it is:
Code:
#==============================================================================

# OneInstance Script

# by Drago del Fato

# Version: 1.0.1

# License: Free for non commercial

# If you use it put me in credits.

#==============================================================================

# [ Instructions ]

# Insert above main.

# In Main Script post this:

# 1. After begin put this:   

#      $instance_test = OneInstance.new

#

# 2. After main loop put this, it should look like:

#   while $scene != nil

#    $scene.main

#  end

#  $instance_test.dispose

#

# 3. Before end put this: 

# rescue SystemExit

#   $instance_test.dispose

#

#

# And you're set. You can edit the name of the token file, and the message

# which will be displayed if an user runs another instance of the game.

# Token file cannot be deleted while the game is running, and after the game

# closes token file is deleted. If people cannot run their game. Say that they,

# need to delete it before running it if in any case it stays (sudden system 

# reboot, power failure or similar)

#==============================================================================

module OneInstanceConsts

  MESSAGE = "ERROR: Another instance of this program is already running."

  TOKEN_FILE = "Active"

end

 

class OneInstance

 

  def initialize

    if FileTest.exists?("./" + OneInstanceConsts::TOKEN_FILE)

      File.delete("./" + OneInstanceConsts::TOKEN_FILE) rescue

      if FileTest.exists?("./" + OneInstanceConsts::TOKEN_FILE)

        print OneInstanceConsts::MESSAGE

        exit! if $DEBUG == false or $DEBUG == nil

       else

        @fToken = File.open("./" + OneInstanceConsts::TOKEN_FILE, "w")

      end

    end

    @fToken = File.open("./" + OneInstanceConsts::TOKEN_FILE, "w")

  end

   

   def dispose

     @fToken.close if !@fToken.closed? 

     File.delete("./" + OneInstanceConsts::TOKEN_FILE) if FileTest.exists?("./" + OneInstanceConsts::TOKEN_FILE)

   end

end

 

It's a tiny modification that goes a fair way :D
 
A much smaller version and just as efficient. No need to modify main either. VX Compatible as well.
Code:
#===============================================================================

# One Game Instance

# Version 1.0

# Author game_guy

#-------------------------------------------------------------------------------

# Intro:

# Prevents players from opening multiple instances of your games.

#

# Features:

# Prevents Multiple Instances

# Custom File/Error

# XP/VX Compatible

# Allows multiple instances in debug mode.

#

# Instructions:

# Place as first script.

# Configure the 2 variables and thats all!

#

# Compatibility:

# Works with everything.

#

# Credits:

# game_guy ~ For creating it.

# ZenVirZan ~ For requesting it.

#===============================================================================

 

# Custom error message.

ERROR = "Instance already running."

# Custom file name, I'd recommend leaving the ENV[Appdata]

TOKEN_FILE = ENV['APPDATA'] + "game_name.token"

 

begin

  if FileTest.exists?(TOKEN_FILE)

    begin

      File.delete(TOKEN_FILE)

    rescue Errno::EACCES

      if $DEBUG == false || $DEBUG == nil || $TEST == false || $TEST == nil

        print ERROR

        exit

      end

    end

  end

  $token = File.open(TOKEN_FILE, "w")

end
 
Great that you want to make it more compact, but since you're already doing it you can delete lines 37 and 40 since they're pretty useless, since you made a if clause which is ALWAYS true, no matter what.

In most Interpreter languages (and also in Ruby) if a variable is not defined and you try to get value from it, you will get nil as value. The reason why Ruby shows errors when you use non-defined variables is when you try to use them with operators +, -, *, / and comparative operators > and <. They are not defined for nil class so when you try to use them you will get an error. Equality operator (==) checks if the value on the left is same as the value on the right, and that will always return false when the value on the left is nil. Only time the non-defined variable will return true is if you try $NONDEFINED == nil, that is always true.

I suppose you tried to make this in a way so that this code doesn't execute when the script is in debug mode (running inside IDE) you should make it like this:

[rgss] 
#===============================================================================
# One Game Instance
# Version 1.0
# Author game_guy
#-------------------------------------------------------------------------------
# Intro:
# Prevents players from opening multiple instances of your games.
#
# Features:
# Prevents Multiple Instances
# Custom File/Error
# XP/VX Compatible
# Allows multiple instances in debug mode.
#
# Instructions:
# Place as first script.
# Configure the 2 variables and thats all!
#
# Compatibility:
# Works with everything.
#
# Credits:
# game_guy ~ For creating it.
# ZenVirZan ~ For requesting it.
#===============================================================================
 
# Custom error message.
ERROR = "Instance already running."
# Custom file name, I'd recommend leaving the ENV[Appdata]
TOKEN_FILE = ENV['APPDATA'] + "game_name.token"
 
begin
  if FileTest.exists?(TOKEN_FILE)
    begin
      File.delete(TOKEN_FILE)
    rescue Errno::EACCES
        if !$TEST && !$DEBUG
          print ERROR
          exit
        end
    end
  end
  $token = File.open(TOKEN_FILE, "w")
end
 
[/rgss]

This would be a right approach to the boolean checking problem. :smile:

Anyways, great way to solve this too. :smile:
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top