• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Lua] Multi-Line In-Game Text / Code Editor

Level 4
Joined
Apr 2, 2023
Messages
10

Code, Documentation, and Demo video all on GitHub.

The built-in WC3 Chat window is only single-line, is tiny, and doesn't support any shortcut keys like Copy/Paste, etc.
This improved text editor essentially embeds a basic word processor into your game. That might seem strange, but in my map I wanted to open a full-screen console / terminal window where a user could type long-form custom code that would actually get executed in-game (think of Minecraft commands / etc). This control simply does the word processing, it won't actually execute the text as code unless you design your map to do that with the LUA Load() function.

Read the code to see how I did it, but essentially I hook into BlzTriggerRegisterPlayerKeyEvent, map all the key presses to an ASCII table, and keep the text in a memory buffer. I render using a TOC/FDF file for escmenutemplates using EscMenuTextAreaTemplate control. I do complex string processing logic on the memory buffer to handle various shortcut keys (CTRL+Z / CTRL+Y for undo/redo, etc), and I do various hacks to prevent the key presses from executing any built-in hotkeys (example: Lock camera in cinematic mode while text editor is visible so DEL key doesn't rotate the camera).

Embedding in your map should be a simple copy/paste of a script file and a TOC file.

If you make any improvements, please send a pull request to my GitHub.

Screenshot.png
 

Attachments

  • Screenshot.png
    Screenshot.png
    1.6 MB · Views: 13
Level 20
Joined
Jul 10, 2009
Messages
479
@speige I currently can't get this to work. Maybe you can help?

I imported the .toc-file as follows:

1682026891461.png

and then executed this code:
Lua:
T = TextEditor:Constructor()
T:SetPositionAndSize(0,1,1,1)
T:SetVisible(true)

But nothing happens on screen. The only noticable effect is that the ingame chat box starts to flicker and closes down quickly after opening it.

When you say that your Text Editor might be suitable for Ingame Consoles, what would the advantage be over using Wc3 native EditBox and TextArea in your opinion?
Wouldn't a typical console consist of a non-controllable TextArea plus a 1-line-EditBox for entering text anyway?
 
Level 4
Joined
Apr 2, 2023
Messages
10
It's working for me. My guess is BlzLoadTOCFile is failing. It returns true/false based on success/fail, so you could print the result to the screen for debugging.

This tutorial explains that BlzLoadTOCFile will fail if the line-endings aren't correct UI: toc-Files
I think GitHub converts to Unix line endings instead of Windows. Maybe try opening that file in a text editor and adding an extra blank line at the end and saving. (If that fixes it, let me know & I'll try to fix my github)

Also, I just noticed that I think the WC3 World Editor is corrupting a small part of my code when saving. I didn't noticed before because I was using an MPQ editor during development instead of the World Editor.
These 2 lines with a % are getting modified after saving in the World Editor. Maybe I need to escape the % character or something?
result = result .. string.format('<0x%02X>', self.Key)
shiftedKeys["5"] = "%"

Here's a video that shows a demo of the control working.

As you said, this could also be done by hacking the native EditBox to appear multi-line by using it in combination with the native read-only TextArea. I considered that approach, but chose this option instead. Both are probably fine, it's a coin toss. I'm assuming that the EditBox would be a slightly worse user experience. I also don't know if BlzTriggerRegisterPlayerKeyEvent stilll works while the EditBox has focus (would need to test), but if not, that'd prevent custom shortcut keys from working.
 
Level 20
Joined
Jul 10, 2009
Messages
479
I got it to work. Needed two solutions.
  1. Downloading the correct file. I thought Git would treat .toc as binary file, so I attempted to download it via Rightclick -> Save to disk from the Github page. That seemed to work, but the file contained the site's html code despite being still named .toc. That's why it shows gigantous 142KB on my screenshot above :D :D
  2. Replacing LF with CRLF was also necessary, as you suggested.

I think GitHub converts to Unix line endings instead of Windows.
The conversion is being done upon committing a change, but you can change that behaviour in the Github settings (Commit Unix-style Linebreaks vs Commit As-Is).

Also, I just noticed that I think the WC3 World Editor is corrupting a small part of my code when saving. I didn't noticed before because I was using an MPQ editor during development instead of the World Editor.
These 2 lines with a % are getting modified after saving in the World Editor. Maybe I need to escape the % character or something?

Yeah, Wc3 needs %% instead of %. Forgetting the second percent-char can even crash your World Editor upon saving your map. Also, it makes your code uninterpretable in other Lua-interpreters.
Better use "\x25" instead of "%" at all times.
Lua:
--This is the right way:
result = result .. string.format('<0x\x2502X>', self.Key)
shiftedKeys["5"] = "\x25"


Regarding your TextEditor, I really like it, good job with it!
I like the most that you cared so much for implementing all of those useful keyboard shortcuts. That goes a long way towards usability.
I also like that you made an explanatory video about it.
Not sure though if you had already seen my existing Ingame Console after you were mentioning in your video that you use your application to execute code with it.


Combining this with @Eikonium's Debug Console would be the precursor to the ultimate testbed.
I looked into it, but I think this is not the right application for Debug Utils, because:
  • can't paste text from outside the map (deal-breaker)
  • no string processing (like "\x30" doesn't convert to "0" and it doesn't process Wc3 color codes). This is not an issue in general, but a direct consequence of the whole frame being an edit box without a submitted part.
  • at least for Debug Utils' console, I want the main window to not be editable, only the bottom line should be
That said, replacing the Wc3 chat input by a native Wc3 edit box might be an enhancement for the Debug Utils console. Might be worth a try to teach it arrow key behaviour (like using up-arrow to access the previous inputs).

Anyway, that's not OP's application's fault. It has its own use cases, some of which @speige already mentioned in the video.


A few other random remarks:
  • Wc3 chat doesn't support arrow keys, but it does support Home/End keys, so you can mark all text while holding the Shift-Key. It also supports copying the marked text and you can paste stuff from outside Wc3 (as long as is contains less than 128 chars).
  • You can use a frame that keeps keyboard focus instead of locking the camera to prevent arrow key / Del / Insert input. This might also fix the unit control group issue, but I'm not sure. Which would actually be important to allow for special char input (anything that requires Shift+Number).
  • Bug Report: Pressing ESC to close the text window down doesn't seem to work on my machine
 
Last edited:
Level 4
Joined
Apr 2, 2023
Messages
10
Thanks a bunch for trying it out and for all the advice.

No, I haven't used your debug console before. I just checked it & it seems super useful. I've just been doing a ton of print statements everywhere for debugging. I'm not very experienced with WC3 map making or lua :(

How would I use a frame that keeps keyboard focus? You mean like a hidden EditBox or something? I should experiment with that. I wonder if it'd prevent
BlzTriggerRegisterPlayerKeyEvent from handling shortcut keys?

I'll fix the line endings & % character in my github.

My video shows using ESC to show/hide the console, but I only implemented that in my own map, not the control itself. I figure other maps may want a different way to open/close the console. You just need to register the keyboard trigger and call SetVisible true/false.
 

Wrda

Spell Reviewer
Level 26
Joined
Nov 18, 2012
Messages
1,890
I think you can have a hidden EditBox by creating it with
BlzGetFrameByName("ConsoleUIBackdrop", 0) as parent, then you can set it outside of game screen. You probably can only do this on map init or something. Tasyen knows a lot about frames, you should ask him if you have any doubts.
 
Last edited:
Level 4
Joined
Apr 2, 2023
Messages
10
@Eikonium @Tasyen
Have either of you testing text highlight & copy/paste using OS clipboard with the native EditBox control? I noticed Elkonium is correct that you can do it with shift+home/end in the native chat window. I assume EditBox is similar? Do you think we could use ForceUIKey to simulate a highlight and copy/paste in EditBox? Might be a hack to get OS clipboard access. I'll experiment when I have time, just thought maybe one of you had already tried it before.
 
Level 20
Joined
Jul 10, 2009
Messages
479
@Eikonium @Tasyen
Have either of you testing text highlight & copy/paste using OS clipboard with the native EditBox control? I noticed Elkonium is correct that you can do it with shift+home/end in the native chat window. I assume EditBox is similar? Do you think we could use ForceUIKey to simulate a highlight and copy/paste in EditBox? Might be a hack to get OS clipboard access. I'll experiment when I have time, just thought maybe one of you had already tried it before.
Yes, EditBox can copy to and paste stuff from the OS clipboard. It also supports arrow key + Shift highlighting out of the box (and holds keyboard focus, so there is no camera movement). No need for workarounds here. Not sure though, if there is a way to still catch key press events to code advanced behaviour.

@Tasyen
Do you know, if there is a way to react to key presses inside EditBox (or similar frames) via trigger? Would be nice to code special behaviour for the Enter-key or others.
 
Top