diff --git a/docs/changelog.txt b/docs/changelog.txt index 01f026da5..c99446bf0 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -43,6 +43,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Fixed special characters in `command-prompt` and other non-console in-game outputs on Linux/macOS (in tools using ``df2console``) - `die`: fixed windows crash in exit handling - `dwarfmonitor`, `manipulator`: fixed stress cutoffs +- `ruby`: fixed calling conventions for vmethods that return strings (currently ``enabler.GetKeyDisplay()``) - `startdwarf`: fixed on 64-bit Linux ## Misc Improvements diff --git a/plugins/ruby/codegen.pl b/plugins/ruby/codegen.pl index ad5f4b239..2a12a1bea 100755 --- a/plugins/ruby/codegen.pl +++ b/plugins/ruby/codegen.pl @@ -462,8 +462,13 @@ sub render_class_vmethods { push @lines_rb, "def $name(" . join(', ', @argnames) . ')'; indent_rb { my $args = join('', map { ", $_" } @argargs); - my $call = "DFHack.vmethod_call(self, $voff$args)"; my $ret = $meth->findnodes('child::ret-type')->[0]; + my $call; + if (!$ret or $ret->getAttribute('ld:meta') ne 'primitive') { + $call = "DFHack.vmethod_call(self, $voff$args)"; + } else { + $call = "DFHack.vmethod_call_mem_return(self, $voff, rv$args)"; + } render_class_vmethod_ret($call, $ret); }; push @lines_rb, 'end'; @@ -534,6 +539,18 @@ sub render_class_vmethod_ret { }; push @lines_rb, "end._at(ptr) if ptr != 0"; } + elsif ($retmeta eq 'primitive') + { + my $subtype = $ret->getAttribute('ld:subtype'); + if ($subtype eq 'stl-string') { + push @lines_rb, "rv = DFHack::StlString.cpp_new"; + push @lines_rb, $call; + push @lines_rb, "rv"; + } else { + print "Unknown return subtype for $call\n"; + push @lines_rb, "nil"; + } + } else { print "vmethod unkret $call\n"; diff --git a/plugins/ruby/ruby-autogen-defs.rb b/plugins/ruby/ruby-autogen-defs.rb index ca5d82393..10727894d 100644 --- a/plugins/ruby/ruby-autogen-defs.rb +++ b/plugins/ruby/ruby-autogen-defs.rb @@ -994,6 +994,14 @@ module DFHack vmethod_arg(a3), vmethod_arg(a4), vmethod_arg(a5)) end + def self.vmethod_call_mem_return(obj, voff, r0=0, a0=0, a1=0, a2=0, a3=0, a4=0) + this = obj._memaddr + vt = df.get_vtable_ptr(this) + fptr = df.memory_read_ptr(vt + voff) + vmethod_do_call(vmethod_arg(r0), fptr, this, vmethod_arg(a0), vmethod_arg(a1), vmethod_arg(a2), + vmethod_arg(a3), vmethod_arg(a4)) + end + def self.vmethod_arg(arg) case arg when nil, false; 0