Jump to content

Tokei

Members
  • Posts

    699
  • Joined

  • Last visited

  • Days Won

    106

Tokei last won the day on May 13

Tokei had the most liked content!

Profile Information

  • Gender
    Male
  • Location
    Canada

Recent Profile Visitors

43528 profile views

Tokei's Achievements

  1. Tokei

    Rsm Editor

    Version 1.0.8

    86 downloads

    Rsm Editor is a tool to edit RSM1 and RSM2 model files from Ragnarok Online. How to install Download the zip archive provided from the download link on this page. Install the application with Rsm Editor Installer.exe; if you are missing a .NET Framework you will be prompted to download it (the tool requires .NET 4.0). Once you are done, you can start the program from the link on your desktop. If you are opening the software for the first time, you'll be prompted with a setting resource window. You can either add a data folder or a list or GRFs from this window. This will be used for loading textures on your models. Key features Can edit both RSM1 and RSM2 file formats. When saving, you can also downgrade or upgrade the model version. The tool uses a different technique for version conversion which should give very accurate results. Position, scale and texture keyframes cannot be converted. Undo and redo for any operation. Quaternions are translated into Euler angles using the YXZ order. Merging different models can be done by right-clicking a mesh node or by drag and dropping another mesh directly. Easy texture modification for each mesh. Enable to set two-faced polygons for the entire model (to avoid invinsible faces in-game). Files can be associated with the tool through Windows (there will not be a setting for this within the software). Backups are created while you are editing the mesh. You can view the list via Debug > Backups manager... Automatically fixes mesh names and root node upon saving. There is no conversion to fbx and vice versa at the moment. Useful shortcuts All shortcuts can be modified via File > Settings > Shortcuts. Pressing Enter on a mesh will center the camera around it. You can quickly duplicate a mesh with Ctrl-C/Ctrl-V. You can hold the Shift key to snap the Gizmo when applying a transformation. You can also hold Shift when selecting a frame. You can select a mesh directly by holding Alt while clicking on it in the viewport. You can enable the wireframe view by pressing F8 or View > Wireframe view. This is useful when positioning meshes. Modifying transform origin The origin position is used for the rotation and scale transformations. To modify, press F1 or View > Show origin, then move the white gizmo. Modifying textures or normals If you click on the model rather than a mesh, you'll have a few more options. Smooth normals is the recommended method. The list of textures can be edited directly. The textures shown in this node are for all meshes together. If you edit the texture locally from your data folder, you can reload the model textures by using Ctrl-R or Transform > Reload model. Animation transform If you've already made an animation for a mesh and you want to apply a rotation (or translation) to all keyframes, you can do so by using the animation transform feature. Press F7 or Animation > Animation transform. This mode applies the transformation to all keyframes at the same time. Keyframes edit You can select multiple keyframes by holding down Shift+LeftMouseButton in the timeline view. You can unselect specific keys by pressing Ctrl+LeftMouseButton. You can move the selected frames by holding down LeftMouseButton. You can copy and paste keys with Ctrl-C/Ctrl-V. You can select all keys with Ctrl-A or deselect all with Ctrl-D. Gizmo orientation By pressing F4 or View > Change gizmo orientation, you can change between global or local orientation. Local orientation sets the gizmo to the current mesh transformation, while global ignores all mesh transformations. Each mesh has local transformations and global transformations (this is unrelated to the gizmo orientation). The difference is that local transformations do not apply to children (not entirely true for RSM2 though). Keyframe transformations always apply to children.
    Free
  2. Hello, if you selected the "Make the ground flat", then the gat tiles will also be set to 0. You'd have to show me what settings you used; though I would guess you probably have another gat file in your RO folder that has a higher priority than your gray map one. I did a quick test on my end and the nif_dun01 map worked fine.
  3. Hello, The easiest way to add new maps is the following: Make sure to update GRF Editor to its latest version (currently on 1.8.9.7, you can use the rAthena page and follow the mediafire link or here: https://www.mediafire.com/file/aflylbhblrzpz0h/ ) Find the new maps in your GRF and then extract the RSW, GND and GAT files. Preferably, use an official GRF since your server's GRF may be encrypted. You can easily test that out by trying to preview the map in GRF Editor. If it doesn't want to load or it throws errors, then the map is encrypted. Open the flat maps maker tool and open the input maps folder by clicking the green arrow: Put the map files you previously extracted in that folder, make sure "Use currently opened GRF" is not checked. If you're using the latest GRF Editor version, you'll get a preview on the right side. You can customize the output rather easily in the options, that part is entirely up to you. Optional. The textures will overwrite the original ones; if that's a concern for you, you can set a unique set of textures for your own map in Options > Maps unique ID (set it to "mine_"). Now generate the gray maps, and you'll get a maps.grf file. You can either add an extra entry in your data.ini file with your new GRF name, or you can merge the two gray map GRFs with the Edit > Merge option. If any error shows up, it will be displayed in the console in the "Generate maps" tab. Now, the reason for your crash is a bit vague. Here are a few possible reasons: You used an old version of GRF Editor or your maps were too recent (kRO released a new map version a while back). Either way, updating GRF Editor will fix that issue. Your GRF priority is wrong in your data.ini. Your maps.grf should have one of the highest priority, so something like: [Data] 0=gepard.grf 1=maps.grf 2=yourserver.grf 3=data.grf You may not have merged the GRF correctly? Not sure how that would crash you though... I can't think of another reason. If the issue persists, can you tell me the map name? I'll just test it on my end to make sure.
  4. This was resolved through PMs a while back; here was the final script for anyone interested: // Act Editor Script - v1.0.5.1 // By Tokeiburu GrfColor textForeground = "0xffffff"; var fontType = "Minecraftia"; var fontSize = 14; var fontBold = true; var dataGrfName = @"C:\mobWithNames\data.grf"; var newGrfName = @"C:\mobWithNames\mobsWithName.grf"; var mobDbPath = @"C:\mobWithNames\mob_db.yml"; var attrFixDbPath = @"C:\mobWithNames\attr_fix.yml"; var jobnamePath = @"C:\mobWithNames\jobname.lub"; var npcIdentityPath = @"C:\mobWithNames\npcidentity.lub"; var oldEncoding = EncodingService.DisplayEncoding; var displayMobNames = false; var maxElementShown = 3; var showFirstElementDamage = true; //var elementTextColors = false; // Fixed settings var mobFolder = @"data\sprite\¸ó½ºÅÍ\"; //jobnamePath = @"C:\Gravity Ragnarok - Copy\data\luafiles514\lua files\datainfo\jobname.lub"; //npcIdentityPath = @"C:\Gravity Ragnarok - Copy\data\luafiles514\lua files\datainfo\npcidentity.lub"; //dataGrfName = @"C:\Gravity Ragnarok - Copy\data.grf"; //newGrfName = @"C:\test\mobsWithName.grf"; //mobDbPath = @"C:\Users\Tokei\Desktop\SVN\rathena4\db\re\mob_db.yml"; //attrFixDbPath = @"C:\Users\Tokei\Desktop\SVN\rathena4\db\re\attr_fix.yml"; var jobname = new JobnameLubData(jobnamePath, npcIdentityPath); int[,,] attr_fix = new int[4, 10, 10]; StringBuilder b = new StringBuilder(); var ele2id = new Dictionary<string, int>(); ele2id["Neutral"] = 0; ele2id["Water"] = 1; ele2id["Earth"] = 2; ele2id["Fire"] = 3; ele2id["Wind"] = 4; ele2id["Poison"] = 5; ele2id["Holy"] = 6; ele2id["Dark"] = 7; ele2id["Ghost"] = 8; ele2id["Undead"] = 9; var id2ele = new Dictionary<int, string>(); foreach (var entry in ele2id) id2ele[entry.Value] = entry.Key; try { EncodingService.DisplayEncoding = EncodingService.ANSI; int ival; string[] values; var mobId2ServerName = new Dictionary<int, string>(); var mobId2ServerElement = new Dictionary<int, int>(); var mobId2ServerElementLevel = new Dictionary<int, int>(); { // Load the attr_fix file var parser = new YamlParser(attrFixDbPath); var body = parser.Output["Body"]; foreach (var entry in body) { int level = Int32.Parse(entry["Level"]) - 1; foreach (var ele2id_entry in ele2id) { var element_name = ele2id_entry.Key; var element_id = ele2id_entry.Value; var def_elements = entry[element_name]; foreach (ParserKeyValue def_ele in def_elements) { attr_fix[level, element_id, ele2id[def_ele.Key]] = Int32.Parse(def_ele.Value); } } } } { // Load the mob_db file var parser = new YamlParser(mobDbPath); var body = parser.Output["Body"]; foreach (var entry in body) { int mobId = Int32.Parse(entry["Id"]); mobId2ServerName[mobId] = entry["Name"]; int eleId = 0; int eleLevel = 0; if (entry["Element"] != null) { eleId = ele2id[entry["Element"]]; } if (entry["ElementLevel"] != null) { eleLevel = Int32.Parse(entry["ElementLevel"]) - 1; } mobId2ServerElement[mobId] = eleId; mobId2ServerElementLevel[mobId] = eleLevel; } } Func<Act, string, int, Act> addNameAbove = (actI, display, offset) => { var pixels = new byte[256 * 20 * 4]; BitmapSource bitmapSource = BitmapSource.Create(256, 20, 96, 96, PixelFormats.Bgra32, null, pixels, 256 * 4); var visual = new DrawingVisual(); using (DrawingContext drawingContext = visual.RenderOpen()) { var ft = new FormattedText(display, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface(fontType), fontSize, new SolidColorBrush(textForeground.ToColor())); if (fontBold) ft.SetFontWeight(FontWeights.Bold); drawingContext.DrawImage(bitmapSource, new Rect(0, 0, 256, 20)); drawingContext.DrawText(ft, new Point(2, 2)); } var image = new DrawingImage(visual.Drawing); var im = new Image { Source = image }; im.Measure(new Size(image.Width, image.Height)); im.Arrange(new Rect(0.0, 0.0, image.Width, image.Height)); im.UpdateLayout(); var grfImage = GrfToWpfBridge.Imaging.ConvertToBitmapSource(im); var transparent = new GrfColor(0, 0, 0, 0); for (int i = 0; i < grfImage.NumberOfPixels; i++) { Buffer.BlockCopy((grfImage.Pixels[4 * i + 3] > 0x80 ? textForeground : transparent).ToBgraBytes(), 0, grfImage.Pixels, 4 * i, 4); } grfImage.Convert(GrfImageType.Indexed8); grfImage.Trim(); grfImage.Margin(2); Buffer.BlockCopy(GrfColor.Black.ToBgraBytes(), 0, grfImage.Palette, 2 * 4, 4); for (int y = 1; y < grfImage.Height - 1; y++) { for (int x = 1; x < grfImage.Width - 1; x++) { if (grfImage.Pixels[y * grfImage.Width + x] == 1) continue; if (grfImage.Pixels[(y - 1) * grfImage.Width + (x)] == 1 || grfImage.Pixels[(y + 1) * grfImage.Width + (x)] == 1 || grfImage.Pixels[(y) * grfImage.Width + (x - 1)] == 1 || grfImage.Pixels[(y) * grfImage.Width + (x + 1)] == 1) grfImage.Pixels[y * grfImage.Width + x] = 2; } } act = actI; // Doesn't support Bgra32 only sprites if (act.Sprite.Palette == null) return act; var unused = act.Sprite.GetUnusedPaletteIndexes().ToList(); if (unused.Count <= 1) return act; if (!act.Sprite.Palette.Contains(textForeground)) Buffer.BlockCopy(textForeground.ToBgraBytes(), 0, act.Sprite.Palette.BytePalette, 4 * unused[0], 4); if (!act.Sprite.Palette.Contains(GrfColor.Black)) Buffer.BlockCopy(GrfColor.Black.ToBgraBytes(), 0, act.Sprite.Palette.BytePalette, 4 * unused[1], 4); var colors = act.Sprite.Palette.Colors.ToList(); var whiteIndex = (byte)colors.IndexOf(textForeground); var blackIndex = (byte)colors.IndexOf(GrfColor.Black); for (int i = 0; i < grfImage.NumberOfPixels; i++) { if (grfImage.Pixels[i] == 1) grfImage.Pixels[i] = whiteIndex; else if (grfImage.Pixels[i] == 2) grfImage.Pixels[i] = blackIndex; } var index = act.Sprite.InsertAny(grfImage); var max = 0; act.AnimationExecute(0, a => a.AllLayers(p => { if ((ival = ((int)(p.ScaleY * p.Height) / 2 - p.OffsetY)) > max) max = ival; })); max += 15; var layer = new Layer(index, grfImage) { OffsetY = -(max + fontSize / 2) + offset }; ival = 0; foreach (var action in act) { // Don't show for the death animation if (ival >= 32 && ival < 40) continue; foreach (var frame in action) { frame.Layers.Add(layer); } ival++; } return act; }; string displayName; int from = -1; var processed = new HashSet<string>(StringComparer.OrdinalIgnoreCase); using (var dataGrf = new GrfHolder(dataGrfName)) using (var outputGrf = new GrfHolder(newGrfName, GrfLoadOptions.New)) { int count = jobname.Id2Sprite.Count; TaskManager.DisplayTaskC("Adding text label", "Processing...", () => from / (float) count * 100f, isCancelling => { try { foreach (var mobEntry in jobname.Id2Sprite.OrderBy(p => p.Key)) { if (isCancelling()) return; var mobResourceName = mobEntry.Value; var mobId = mobEntry.Key; //b.AppendLine(mobId + "\t" + mobResourceName + "\t" + processed.Contains(mobResourceName)); if (processed.Contains(mobResourceName)) { from++; continue; } if (mobId2ServerName.ContainsKey(mobId)) { displayName = mobId2ServerName[mobId];//.ToUpper(); processed.Add(mobResourceName); } else { displayName = jobname.Id2Job[mobId].Replace("JT_", "").Replace("_", " ");//.ToUpper(); } var actEntry = dataGrf.FileTable.TryGet(GrfPath.Combine(mobFolder, mobResourceName + ".act")); var sprEntry = dataGrf.FileTable.TryGet(GrfPath.Combine(mobFolder, mobResourceName + ".spr")); if (actEntry == null || sprEntry == null) { from++; continue; } var mobAct = new Act(actEntry, new Spr(sprEntry)); StringBuilder e_builder = new StringBuilder(); if (mobId2ServerName.ContainsKey(mobId)) { int eleLevel = mobId2ServerElementLevel[mobId]; int eleId = mobId2ServerElement[mobId]; var dmgElements = new Dictionary<int, int>(); for (int i = 0; i < 9; i++) { dmgElements[i] = attr_fix[eleLevel, i, eleId]; } int highest = -1; int max = maxElementShown; foreach (var dmgElement in dmgElements.OrderByDescending(p => p.Value)) { if (dmgElement.Value < highest) break; max--; if (max < 0) { e_builder.Append("..."); break; } highest = dmgElement.Value; if (e_builder.Length == 0) e_builder.Append(id2ele[dmgElement.Key] + (showFirstElementDamage ? " (" + dmgElement.Value + "%)" : "")); else e_builder.Append(" - " + id2ele[dmgElement.Key]); } mobAct = addNameAbove(mobAct, e_builder.ToString(), 0); if (displayMobNames) mobAct = addNameAbove(mobAct, displayName, 15); } else { if (!displayMobNames) { from++; continue; } mobAct = addNameAbove(mobAct, displayName, 0); } MemoryStream actStream = new MemoryStream(); MemoryStream sprStream = new MemoryStream(); try { mobAct.SaveWithSprite(actStream, sprStream); } catch { from++; continue; } outputGrf.Commands.AddFile(actEntry.RelativePath, actStream); outputGrf.Commands.AddFile(sprEntry.RelativePath, sprStream); if (from % 200 == 0) { GC.Collect(); outputGrf.QuickSave(); outputGrf.Reload(); } from++; } } catch (Exception err) { ErrorHandler.HandleException(err); } finally { outputGrf.QuickSave(); from = count; } }); //ErrorHandler.HandleException(b.ToString()); } } catch (Exception err) { ErrorHandler.HandleException(err); } finally { EncodingService.DisplayEncoding = oldEncoding; }
  5. There are no versions that allow you to make a quadtree. You'll need BrowEdit 3 for map edits. Though, if you... really want to try older versions, you can do so from the rAthena download page at the bottom (here (Version 1.0.1 is quite catchy... ahem!)
  6. You don't need to close grf2, but grf1 will be used and overwritten, so yes it needs to be closed. You don't have to do that if it's currently opened by GRF Editor, it will close and reopen it automatically.
  7. This isn't a GRF, or it's encrypted from a third party tool. So there's not much to do here. Changing the header won't do much.
  8. I'll be looking into this one. Though I need to remake the lub decompiler, it's... a bit nasty. Well, as it says, you're run out of memory. This is hard to reach however, especially GRF Editor is released in x64 and there's practically no memory limit. Make sure you've updated to 1.8.8.8 and see if that resolved your issue.
  9. Hmm, is that even a GRF...? You'd have to show me the first ~50 bytes of the GRF (or upload the GRF somewhere) to have a look. If you have to manually change the header, something's definitely not right here. The magic header is always Master of Magic. (Also, that color theme is quite broken. That's not how it's supposed to look at all.)
  10. That's normal. It doesn't really make sense to send a new walking packet for your own character after using @refresh. But you can forcefully send it again in the clif_refresh function (in clif.cpp). Just add the following at the end of the function. struct unit_data* ud = unit_bl2ud(&sd->bl); if (ud && ud->walktimer != INVALID_TIMER) { unit_walktoxy(&sd->bl, ud->to_x, ud->to_y, 4); } Though, it will look a tad weird because the character has to walk from a center cell, so it will "walk back" when using @refresh. You could also send a "unit_stop_walking(&sd->bl, USW_NONE);" if you want the character to stop moving instead. Whichever you prefer.
  11. Hello, I'll be adding a better guideline on the encryption window as I can understand the confusion there. You are correct, the GRF Encryption tool window is only meant to create the client files (client.exe + cps.dll). The "Encrypt GRF" option was removed from that window because it was redundant. To encrypt your GRF, you have to right-click a folder and select encrypt: This does the same thing as the previously removed option. That is also how you're supposed to encrypt your Thor patches when you want to patch encrypted content. As for the password prompt when opening the GRF, that is mostly for visual effect in the first place. An encrypted GRF may not have this prompt. Also, the GRFs can be partially encrypted, so if you choose "Cancel" when this prompt shows up, you can still browse the GRF depending on what you did.
  12. Updated to 1.8.8.4 to fix this issue. The flat maps tool has been updated as well. Hello, Which client version are you using? Which version of GRF Editor are you using? Which Visual C++ redistributables version did you install?
  13. The emblem issue should be fixed in 1.8.8.2.
  14. Hmm, alright, since I'm unable to reproduce this issue on my end, I can only go with a trial and error approach. @Mister Noob @LearningRO @Vashtido Please PM me on Discord (tokei / 95599057182920704) if you're willing to help figure out the issue. I'll be sending you unprotected debug versions of the encryption tool.
  15. I was unable to reproduce the issue. Can you show me what the emblem received by the emulator was? It will be stored in your SQL database in the "guild" table under the "emblem_data" field. (You should check the previous field first of course.)
×
×
  • Create New...