pleonex / tinke Goto Github PK
View Code? Open in Web Editor NEWViewer and editor for files of NDS games
License: GNU General Public License v3.0
Viewer and editor for files of NDS games
License: GNU General Public License v3.0
Then you should make free Maximum value of the "Tile Offset" numeric field.
Or!!!
Don't adding tilePos to OAM.tile_offset and correct supported Partitions of tiles data (see issue #18)
The game Apollo Justice has a custom image format. And custom archives.
As usual, I have code for dealing with them.
The current Images plugin does not support image files with a tile width different to the tile height. That is, all the tiles must be squares. This is not the case of some images. Most image algorithms must be implemented again and checked to implemented this feature.
NinoImager implements these feature so it could be used as reference.
How to run it on linux?
If I build a SWAR file using SWAVtoSWAR, and then I attempt to replace the original SWAR in the ROM, it works if the new SWAR is smaller than the original or even if it's slightly bigger, but if it's considerably bigger (I haven't tried to find out exactly how much), it stops working ingame. I don't know if this is an issue over all games; the only one I've tried this with is Pokemon HeartGold. I'm not entirely sure what causes this issue, but I went in with a hex editor after replacing it and I think some of the headers in the SDAT had incorrect sizes and offsets. I don't think it's a problem with actual lack of size; there's plenty of free space in the ROM and I've seen SDATs (and SWARs for that matter) get much bigger than the one I'm trying to replace. I can provide files if you wish.
Something odd to note: Ripping NCSFs from the ROM still works, even though the SDAT itself doesn't work ingame. I don't know if this tells you anything or not.
I'm using Tinke 0.9.0.0, when I click the Info section after I open a .sdat file, it gives the following error:
System.OverflowException: The value was too large or too small for an unassigned byte.
in System.Decimal.ToByte(Decimal value)
in SDAT.InfoForm.numericPLAYER_ValueChanged(Object sender, EventArgs e)
in System.Windows.Forms.NumericUpDown.OnValueChanged(EventArgs e)
in System.Windows.Forms.NumericUpDown.set_Value(Decimal value)
in SDAT.InfoForm.ReadRecord(Int32 page)
in SDAT.InfoForm.ReadInfo()
in SDAT.InfoForm..ctor(Info info)
in SDAT.iSDAT.btnInfoSect_Click(Object sender, EventArgs e)
in System.Windows.Forms.Control.OnClick(EventArgs e)
in System.Windows.Forms.Button.OnClick(EventArgs e)
in System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
in System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
in System.Windows.Forms.Control.WndProc(Message& m)
in System.Windows.Forms.ButtonBase.WndProc(Message& m)
in System.Windows.Forms.Button.WndProc(Message& m)
in System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
in System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
in System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
I'm trying to edit the .sdat of an english Pokémon HeartGold ROM. If I click continue, and click again on the button, it opens the info section normally, but after I make my changes and click 'Accept', the 'Save SDAT' button does not save any changes. Sometimes, clicking this button crashes the ROM.
How I can be use of this function? PluginHost.cs line 142
public void Decompress(byte[] data)
{
string temp = Get_TempFile();
System.IO.File.WriteAllBytes(temp, data);
DescompressEvent(temp);
try { System.IO.File.Delete(temp); }
catch { }
}
How get or find of decompressed data? Or temp file name?
It is ridiculous how many games reinvent the wheel with custom archives and image formats.
Yada yada, game with custom archive.
I always confuse the two methods: LinearToHorizontal and inverse.
I understand that LinearToHorizontal converts linear bytes order to tiled... but
for images this is backward action.
For example, LinearToHorizontal method:
I loaded a Bitmap image and I want to get tiled bytes order.
After Indexing of the my bmp Image I have linear bytes order. Allright?
First row of the my image is first bytes...
But for my result tiled image (first bytes must be from first tile) I use HorizontalToLinear method, because LinearToHorizontal take first bytes of 1 tile (from linear image?) and reordered this bytes as for linear image...
Sorry for the issue... :)
I understand your logic of this methods... now :)
About partitions:
Then Bank.partitionOffset must be using in next methods of Ekona.Images:
0) put new variable in Bank structure: partitionOffset (and may be partitionDataSize).
a) Actions.cs: GetImage(Bank ...)
cell_img.StartByte = (int)(tileOffset * 0x20 + bank.partitionOffset);
b) SpriteControl.cs: Import_File(string path, int banki)
uint addedSize = 0;
...
// Get the data of a oam and add to the end of the image
for (int i = 0; i < oams.Length; i++)
{
...
// If Add image is checked add the new image to the end of the original file...
No, adding a new image to the end of the partition block.
In this should be wroten other Add_Image method with insert data position.
if (radioImgAdd.Checked)
{
uint offset = Actions.Add_Image(ref imgData, cellImg, (uint)(1 << (int)sprite.BlockSize) * 0x20) - sprite.Banks[banki].partitionOffset;
offset /= 0x20;
offset >>= (int)sprite.BlockSize;
addedSize += cellImg.Length;
if (offset >= 0x400) throw new Exception("???");
oams[i].obj2.tileOffset = offset;
oams[i].obj1.flipX = 0;
oams[i].obj1.flipY = 0;
}
else // Replace the old image
{
uint tileOffset = oams[i].obj2.tileOffset;
tileOffset = (uint)(tileOffset << (byte)sprite.BlockSize) * 0x20 + sprite.Banks[banki].partitionOffset;
Array.Copy(cellImg, 0, imgData, tileOffset, cellImg.Length);
}
}
if (addedSize > 0)
for (int i = banki + 1; i < sprite.Banks.Length; i++) sprite.Banks[i].partitionOffset += addedSize;
c) several changes in the NCER.cs of the Images plugin
see: https://groups.google.com/forum/#!topic/tinke/q8Nt88UJ5zQ
=> In result file2 rewrite file1 (on HDD) and path in tinke has link to file1.
File1 will not be restored.
Another game that hides everything in a custom archive.
My unpacker as usual.
After opening and saving (without changes) trimmed rom (fo example after ndstool) "header crc" has invalid value, but recalculated. Header size value is OK. Therefore I don't reopening issue #16.
After opening the newest rom and saving I get a valid rom.
Would be good if it automatically decompressed a file when it is selected.
Maybe also an option to "decompress all"?
0.9.0 does not recognize the utility.bin of this ROM http://datomatic.nointro.org/index.php?page=show_record&s=28&n=x198
Could this please be added to the release?
I cannot compile myself.
Thanks
Hi
To restore color componetnt (R, G, B or A) from x-bit representation (RGB555 for example, x = 5) we need max value (0x1F) convert to 0xFF - max value for 8-bit color.
You use formula: C(R/G/B/A) * 8 - is incorrect.
Nvidia Texture tools and squish using the next formula for restore x-bit color component (Cx) to 8-bit representation (C8) (for x >= 4)
C8 = (Cx << (8 - x)) | (Cx >> (x - (8 - x)));
This formula hardest if x < 4 (and for all cases):
C8 = Sum(Cx << (8 - i * x)); // while i * x < 4
C8 |= Cx >> x - (8 - last(i) * x));
for 5-bit representation of Red component this formula have view: R = (R << 3) | (R >> 2);
for 6-bit representation of Green component this formula have view: G = (G << 2) | (G >> 4);
for 3-bit representaion of Alpha: A = (A << 5) | (A << 2) | (A >> 1);
Nvidia Texture tools in last version optimize method for fast RGB565 convert:
static Color32 bitexpand_color16_to_color32(Color16 c16) {
Color32 c32;
//c32.b = (c16.b << 3) | (c16.b >> 2);
//c32.g = (c16.g << 2) | (c16.g >> 4);
//c32.r = (c16.r << 3) | (c16.r >> 2);
//c32.a = 0xFF;
c32.u = ((c16.u << 3) & 0xf8) | ((c16.u << 5) & 0xfc00) | ((c16.u << 8) & 0xf80000);
c32.u |= (c32.u >> 5) & 0x070007;
c32.u |= (c32.u >> 6) & 0x000300;
return c32;
}
ImageLib using next formula for all cases:
C8 = Cx * 255 / max(Cx); where max(Cx) = (2^x) - 1 or max = (1 << x) - 1;
for 5-bit representation of Red: R = R * 255 / 31;
for 3-bit representaion of Alpha: A = A * 255 / 7;
for 4-bit representaion of Alpha: A = A * 255 / 15; // A *= 17;
You need to fix this in next methods and classes:
Ekona/Images/Actions.cs
public static Color BGR555ToColor(byte byte1, byte byte2)
public static Byte[] AlphaIndexTo32ARGB(Color[] palette, byte[] data, ColorFormat format)
// for alpha parameter
public static Color Get_Color(Byte[] data, Color[] palette, ColorFormat format, ref int pos)
Plugins/3DModels/3DModels/BTX0.cs
private static Bitmap Draw_Texture(IPluginHost pluginHost, sBTX0 btx0, byte[] data, sBTX0.Texture.TextInfo info, Color[] palette)
game I am inspecting has lots of decompressed assets.
would be great to be able to save the rom with decompressed assets to save to have to decompress them every time I open them?
Only when Italian (it-IT) is the program language. All plugins are already translated to French and Spanish. The issue is a reference to pull request #65 used to add Italian translations for plugins.
My visions of the good issue:
Tinke: 4.5 or hightest with time
Ekona, DSDecmp: only 3.5 for compatible all developers (may be I is one?)
Plugins: 3.5 as base for compatible with a early Tinke version, but can hightest if necessary (new features of new versions).
This one's a two-parter.
The first (and most easily fixable) part is that the script outputs the following error when checking for a previous build dir:
./compile.sh: line 38: [: /home/alicethegorgon/Projects/DS: binary operator expected
The solution is to change:
# Remove previous builds
if [ -d $BUILD_DIR ]; then
echo "Deleting old build directory"
rm -rf $BUILD_DIR
fi
into:
# Remove previous builds
if [ -d "$BUILD_DIR" ]; then
echo "Deleting old build directory"
rm -rf "$BUILD_DIR"
fi
(Note the quotation marks around both instances of $BUILD_DIR
in the fixed one.)
The second problem is that xbuild errors out when compiling plugins, and gives the following error:
Compiling plugin Plugins/LAYTON/LAYTON.sln...
Error compiling Plugins/LAYTON/LAYTON.sln. Aborting.
MSBUILD: error MSBUILD0004: Too many project files specified
The solution seems to be getting rid of the line:
XBUILD_PLUGINS="$XBUILD;OutputPath=$BUILD_DIR/Plugins/"
And changing:
$XBUILD_PLUGINS "$1" > build.log
into:
$XBUILD "/p:OutputPath=$BUILD_DIR/Plugins/" "$1" > build.log
So that it follows the same format as the (working) compilation of tinke.
I have no idea why you can't just change the XBUILD_PLUGINS definition from:
XBUILD_PLUGINS="$XBUILD;OutputPath=$BUILD_DIR/Plugins/"
into:
XBUILD_PLUGINS="$XBUILD /p:OutputPath=$BUILD_DIR/Plugins/"
but for some reason it doesn't work, and gives the same "Too many project files" error.
Also, sorry for not submitting a pull request with these changes. I'm pretty new to git, and it's late, and I really don't want to delve into that whole process right now.
I've attached the modified file though, so it should be easy to toss into the directory and compare and push the changes. (Github won't let me upload it as a ".sh" file, so I've zipped it up first.)
compile.sh.zip
For charmap type = 1 (CMAP section of NFTR) the char_code array length gets by wrong calculation:
line 146: type1.char_code = new ushort[(pamc.block_size - 0x14 - 0x02) / 2];
In accordance with N**RO-SDK its must have value by next formula:
type1.char_code = new ushort[pamc.last_char - pamc.first_char + 1];
in Project property target framework value is 3.5 and .bat script use only compilator ver 4.0
For example: if offset for a glyph is 0xFF then its equals to -1.
See of the file that attached at #42 for checking of this on the "J" character.
Hi!
I implemented import image of an "arc" files of the Pr. Layton. For one of this files reading/decompressing is wrong:
http://file.qip.ru/file/7W6WBBd4/wifimenu_sub.html
This is russian version of file and created by another tools, but it correctly opening in the game.
Go to LAYTON/Bg.cs in method Read()
to line pluginHost.Decompress(temp);
after execution of this line decompressed file has contain compressed data in first and valid decompressed in last.
But i include in dependences DSdecmp dll and change this line to:
fileIn = Path.GetDirectoryName(temp) + Path.DirectorySeparatorChar + "de" + Path.DirectorySeparatorChar + Path.GetFileName(temp);
Directory.CreateDirectory(Path.GetDirectoryName(fileIn));
DSDecmp.Main.Decompress(temp, fileIn, DSDecmp.Main.Get_Format(temp));
Then result is correct.
I see, that pluginHost.Decompress(temp)
using Decompress method (public static void Decompress(string input, string output)
) in DSdecmp.Main class, which may be return invalid decompressed stream or detected invalid format?
DecompressEvent
in Tinke project use DSDecmp.Main.Get_Format(temp)
to detect invalid format but not using this in later:
FormatCompress compressFormat = DSDecmp.Main.Get_Format(arg);
if (compressFormat != FormatCompress.Invalid)
DSDecmp.Main.Decompress(arg, dec_file, compressFormat);
May be better it will be so DSDecmp.Main.Decompress(arg, dec_file, compressFormat);
?
Or replace code with detection of compress formats in DSDecmp.Main.Decompress() method by DSDecmp.Main.GetFormat() ? Or both changes is better?
Or my file is invalid? But if I decompressing this by Tinke GUI from combo box "Open As" with action "Compress" from 0x4 offset - all correct.
Support wild magic textures, as seen in Totally Spies 2.
I have a working decoder.
Hello, I'm attempting to insert a new snare sample into Pokémon White 2, and decided to use Tinke for it. I go to import the sample, and it plays fine in Tinke. I clicked 'Save SDAT', and attempted to reinsert back into the game. However, the sample seems to not have saved because the original one that I replaced still plays. And when I open the SDAT in Tinke, it seems to just play the original sample.
I even clicked on "pack" before saving the SDAT, but that only makes it worse, actually breaking the entire SDAT.
Hi! For fonts in 3-bit format the "Tiles" array of bits can have length not a multiple of three.
And we get "Index out of range" Exception on GetChar in row (434):
for (int i = 0; i < tiles.Length; i += depth)
This is fix to this:
for (int i = 0; i <= tiles.Length - depth; i += depth)
File for example (from game):
http://clq.ru/kL/wug21
If a changes files in rom (with "Change file" button) and rom data size of new ROM increases.
Then after saving field with data size of the new rom in .nds header (0x80) has been not changed.
In this data size should be change and recalculate all CRC16.
Value of size must be = bigest offset of file (in fat) + size of this file.
In Professor Layton and the Curious Village the images in .arc format can be viewed and exported, but the import functionality is missing.
Are there any plans on adding this functionality, and if not can someone give me the format of the file so I can try to make one myself?
Not sure this is an "issue" per se but I don't know where else to do this.
Starting the release 0.9.0 on Windows give a system exception with FileNotFound
and the keyword CLR20r3
. Checked that .NET 4.5.2 was installed.
Maybe because it was compiled on Mono?
Why can't capcom just use one format?
In RawData.cs,
method: override void Write(string fileOut, PaletteBase palette)
line 224:
for (int i = image_size + StartByte; i < ori_data.Length; i++)
This is never be to write last data from ori_data
Maybe???:
for (int i = Tiles.Length + StartByte; i < ori_data.Length; i++)
We should use a CI service to avoid situations where a change break other plugins like in #28.
If I create raw palette or image entity without real FAT id then on importing of a new image I see Error Message with text:
Cause of this in next lines (ImageControl.cs in Ekona):
private void Save_Files()
{
if (image.ID >= 0)
{
try
{
string imageFile = pluginHost.Get_TempFolder() + Path.DirectorySeparatorChar + Path.GetRandomFileName() + image.FileName;
image.Write(imageFile, palette);
pluginHost.ChangeFile(image.ID, imageFile);
}
catch (Exception e) { MessageBox.Show("Error writing new image:\n" + e.Message); };
}
if (palette.ID >= 0 && radioReplacePal.Checked)
{
try
{
string paletteFile = pluginHost.Get_TempFolder() + Path.DirectorySeparatorChar + Path.GetRandomFileName() + palette.FileName;
palette.Write(paletteFile);
pluginHost.ChangeFile(palette.ID, paletteFile);
}
catch (Exception e) { MessageBox.Show("Error writing new palette:\n" + e.Message); };
}
if (isMap && map.ID >= 0)
{
try
{
string mapFile = pluginHost.Get_TempFolder() + Path.DirectorySeparatorChar + Path.GetRandomFileName() + map.FileName;
map.Write(mapFile, image, palette);
pluginHost.ChangeFile(map.ID, mapFile);
}
catch (Exception e) { MessageBox.Show("Error writing new map:\n" + e.Message); };
}
}
Because the image.ID and palette.ID has zero as default value.
This is issue will be fixed on Pull Request #31 in last update.
Images with a map file uses more than one palette. For instance, a 4 bpp depth image with map file could use 16 palettes with 16 colors in the same image, in total it could have 256 colors. Tinke only checks that the number of unique colors is not more than 1 << depth
, so in this case it would refuse the image since it would have more than 16 colors.
We would need to check if the map compression algorithm support checking for more than one palette so we would need just to update the check condition.
public static int FindNextColor(Color c, Color[] palette, decimal threshold = 0)
in Ekona.Images.Actions.cs
If a color represented as vector with coordinates R G B
Distance between two vector equals to |x - y|
Then the threshold value is a radius of a toleranced sphere.
But in the FindNextColor method distance calculated as | |x| - |y| |...
Error or I'm not understanding of a color spectre stucture...
I am currently translating Professor Layton, there are thousands of .txt files compressed into .pcm folders. Currently I have to replace every single file and then pack them. Is there any way to compress the whole folder with files to .pcm file and then replace just the compressed file?
¿Pleonex, podrías añadir soporte para los archivos bin de este juego (cpac_models.bin, cpac_stage_mg.bin, etc.)?
When imported new map, nPalette in NTFS structure always = 0
But palette number in Map Control window selected > 0, and palette replaced/swaped to this palette.
I see solution of this problem in next changes:
// Create a map file
if (isMap && checkMapCmp.Checked)
map.Set_Map(Actions.Create_Map(ref tiles, image.BPP, image.TileSize, (byte)numPal.Value), map.CanEdit, bitmap.Width, bitmap.Height);
else if (isMap)
{
int num_tiles = (tiles.Length * 8 / image.BPP) / (image.TileSize * image.TileSize);
map.Set_Map(Actions.Create_BasicMap(num_tiles, 0, (byte)numPal.Value), map.CanEdit);
}
Also, in several lines tile_size used as constant 8. This is true?
When opening the dutch version of LAYTON2 (Professor Layton en de Doos van Pandora) in Tinke, only very few files are recognized (17%) by Tinke, while when opening the English (and some other) versions it detects most files (93%).
I changed the Game code from YLTH to YLTS and all (image) files seem to work just fine. I can see from the code that the Game code is checked and this is probably why so many files aren't recognized for the Dutch version (when you use the original YLTH Game code).
So basicly the Game code for the Dutch version of LAYTON2 should be added to the plugin.
(I'm running Tinke through Wine Mono on Mac OS X using the Crossover app)
Hi, I am hacking Pang DS rom file.
https://en.wikipedia.org/wiki/Pang:_Magical_Michael
Files are named as follows:
filename_type_compression.bin
for example:
block_ncg_LZ.bin
block_ncl_LZ.bin
stage461b_nsc_LZ.bin
stage461t_nsc_LZ.bin
In Tinke 0.8.1 these files were correctly opened by:
In Tinke 0.9.0 these files cannot be opened easily
If I "unpack" I can see the header bytes of each file:
for example:
block_ncg_LZ.bin [RGCN]
block_ncl_LZ.bin [RLCN]
stage461b_nsc_LZ.bin [RCSN]
stage461t_nsc_LZ.bin [RCSN]
It would be good if 0.9.x could recognise these files by content if there is no filename match?
"Recognized files" drops from 99% in 0.8.1 to 98% in 0.9.0
Otherwise, what do I have to do to easily open these file types in 0.9.x?
Thought: is it possible my plugins folder is not being found for some reason?
Thanks!
For example for solutions, i implement in my Map Editor additional import options:
Implementation not hard, but its problem looked in every second game...
After #21 pull request the Images plugin is not compiling because we have changed some structures in Ekona.
Tinke fails when loading any rom.
I'm running Fedora 22 x64 with mono 4.0.2.5
Log:
$ mono Tinke.exe
WARNING: The runtime version supported by this application is unavailable.
Using default runtime: v4.0.30319
Could not set X locale modifiers
<b>Analysing game:</b> Metroid Prime Hunters (E).nds
<b>Game information:</b><br>MP HUNTERS (AMHP)
Metroid Prime Hunters
Nintendo
System.NullReferenceException: Object reference not set to an instance of an object
at Tinke.Nitro.FNT.ReadFNT (System.String romFile, UInt32 fntOffset, sFAT[] fat, Tinke.Acciones accion) [0x00000] in <filename unknown>:0
at Tinke.Sistema.ReadGame (System.String file) [0x00000] in <filename unknown>:0
at Tinke.Sistema.Sistema_Load (System.Object sender, System.EventArgs e) [0x00000] in <filename unknown>:0
at System.Windows.Forms.Form.OnLoad (System.EventArgs e) [0x00000] in <filename unknown>:0
at System.Windows.Forms.Form.OnLoadInternal (System.EventArgs e) [0x00000] in <filename unknown>:0
It's now running natively on my Mac, albeit with some window redraw issues. Thanks for help so far
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.