Я нашел решение, которое полностью исключает ненадежную реализацию именованных каналов Cygwin. У Windows есть собственное средство именованных каналов, и есть даже Ruby Gem под названием win32-pipe , который использует его.
К сожалению, похоже, нет способа использовать Ruby Gems в сценарии RGSS; но, разобрав гем win32-pipe, я смог внедрить ту же идею в игру RGSS. Этот код - необходимый минимум для записи игровых событий в реальном времени на обратный канал, но он может быть очень полезен для глубокой отладки.
Я добавил новую страницу сценария прямо перед «Основным» и добавил:
module PipeLogger
# -- Change THIS to change the name of the pipe!
PIPE_NAME = "RGSSPipe"
# Constant Defines
PIPE_DEFAULT_MODE = 0 # Pipe operation mode
PIPE_ACCESS_DUPLEX = 0x00000003 # Pipe open mode
PIPE_UNLIMITED_INSTANCES = 255 # Number of concurrent instances
PIPE_BUFFER_SIZE = 1024 # Size of I/O buffer (1K)
PIPE_TIMEOUT = 5000 # Wait time for buffer (5 secs)
INVALID_HANDLE_VALUE = 0xFFFFFFFF # Retval for bad pipe handle
#-----------------------------------------------------------------------
# make_APIs
#-----------------------------------------------------------------------
def self.make_APIs
$CreateNamedPipe = Win32API.new('kernel32', 'CreateNamedPipe', 'PLLLLLLL', 'L')
$FlushFileBuffers = Win32API.new('kernel32', 'FlushFileBuffers', 'L', 'B')
$DisconnectNamedPipe = Win32API.new('kernel32', 'DisconnectNamedPipe', 'L', 'B')
$WriteFile = Win32API.new('kernel32', 'WriteFile', 'LPLPP', 'B')
$CloseHandle = Win32API.new('kernel32', 'CloseHandle', 'L', 'B')
end
#-----------------------------------------------------------------------
# setup_pipe
#-----------------------------------------------------------------------
def self.setup_pipe
make_APIs
@@name = "\\\\.\\pipe\\" + PIPE_NAME
@@pipe_mode = PIPE_DEFAULT_MODE
@@open_mode = PIPE_ACCESS_DUPLEX
@@pipe = nil
@@buffer = 0.chr * PIPE_BUFFER_SIZE
@@size = 0
@@bytes = [0].pack('L')
@@pipe = $CreateNamedPipe.call(
@@name,
@@open_mode,
@@pipe_mode,
PIPE_UNLIMITED_INSTANCES,
PIPE_BUFFER_SIZE,
PIPE_BUFFER_SIZE,
PIPE_TIMEOUT,
0
)
if @@pipe == INVALID_HANDLE_VALUE
# If we could not open the pipe, notify the user
# and proceed quietly
print "WARNING -- Unable to create named pipe: " + PIPE_NAME
@@pipe = nil
else
# Prompt the user to open the pipe
print "Please launch the RGSSMonitor.rb script"
end
end
#-----------------------------------------------------------------------
# write_to_pipe ('msg' must be a string)
#-----------------------------------------------------------------------
def self.write_to_pipe(msg)
if @@pipe
# Format data
@@buffer = msg
@@size = msg.size
$WriteFile.call(@@pipe, @@buffer, @@buffer.size, @@bytes, 0)
end
end
#------------------------------------------------------------------------
# close_pipe
#------------------------------------------------------------------------
def self.close_pipe
if @@pipe
# Send kill message to RGSSMonitor
@@buffer = "!!GAMEOVER!!"
@@size = @@buffer.size
$WriteFile.call(@@pipe, @@buffer, @@buffer.size, @@bytes, 0)
# Close down the pipe
$FlushFileBuffers.call(@@pipe)
$DisconnectNamedPipe.call(@@pipe)
$CloseHandle.call(@@pipe)
@@pipe = nil
end
end
end
Чтобы использовать это, вам нужно только позвонить PipeLogger::setup_pipe
перед тем, как написать событие; и позвоните PipeLogger::close_pipe
перед выходом из игры. (Я помещаю вызов установки в начало «Main» и добавляю предложение ensure
для вызова close_pipe
.) После этого вы можете добавить вызов к PipeLogger::write_to_pipe("msg")
в любой точке любого сценария с любой строкой для msg и напиши в трубу.
Я проверил этот код с помощью RPG Maker XP; он также должен работать с RPG Maker VX и более поздними версиями.
Вам также понадобится что-то, чтобы прочитать ОТ канала. Есть несколько способов сделать это, но самый простой - это использовать стандартную установку Ruby, Ruby Gem из win32-pipe и этот скрипт:
require 'rubygems'
require 'win32/pipe'
include Win32
# -- Change THIS to change the name of the pipe!
PIPE_NAME = "RGSSPipe"
Thread.new { loop { sleep 0.01 } } # Allow Ctrl+C
pipe = Pipe::Client.new(PIPE_NAME)
continue = true
while continue
msg = pipe.read.to_s
puts msg
continue = false if msg.chomp == "!!GAMEOVER!!"
end
Я использую Ruby 1.8.7 для Windows и win32-pipe gem , упомянутые выше (см. здесь для хорошей ссылки по установке гемов). Сохраните вышеупомянутое как "RGSSMonitor.rb" и вызовите его из командной строки как ruby RGSSMonitor.rb
.
ПРЕДОСТЕРЕЖЕНИЯ:
- Указанный выше код RGSS хрупок; в частности, он не обрабатывает сбой при открытии именованного канала. Обычно это не проблема на вашей собственной машине для разработки, но я бы не рекомендовал отправлять этот код.
- Я не проверял это, но я подозреваю, что у вас будут проблемы, если вы запишете много вещей в журнал без запуска процесса чтения канала (например,
RGSSMonitor.rb
). Именованный канал Windows имеет фиксированный размер (я установил здесь 1 КБ), и по умолчанию записи будут блокироваться после заполнения канала (поскольку ни один процесс не «снимает давление» путем чтения из него). К сожалению, движок RPGXP уничтожит скрипт Ruby, который остановился на 10 секунд. (Мне сказали, что RPGVX исключил эту сторожевую функцию - в этом случае игра будет зависать, а не прерываться.)