Last active
December 22, 2021 12:26
-
-
Save nkrapivin/8fc282f163a50bede7b2383b93f83cbe to your computer and use it in GitHub Desktop.
coded quickly in a few hours
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// @function TGINAssert(assertExpr, assertMsg) | |
/// @description assert() like function, do not use in your game code. | |
/// @param {bool} assertExpr boolean-ish exception | |
/// @param {string} assertMsg string that will be used if an assertion had failed. | |
/// @returns nothing, throws on error | |
function TGINAssert(assertExpr, assertMsg) { | |
if (!assertExpr) | |
throw string_replace("TGINParse: Assertion Failed: %s", "%s", string(assertMsg)); | |
} | |
function TGINGroup(_name, _sprites, _spinesprites, _fonts, _tilesets, _texpages) constructor { | |
// public: | |
name/*:string*/ = _name; | |
sprites/*:int[]*/ = _sprites; | |
spinesprites/*:int[]*/ = _spinesprites; | |
fonts/*:int[]*/ = _fonts; | |
tilesets/*:int[]*/ = _tilesets; | |
texpages/*:int[]*/ = _texpages; | |
} | |
function TGINString(buf, offs) { | |
var _addr = buffer_read(buf, buffer_u32); | |
var _old = buffer_tell(buf); | |
var _str = undefined; | |
buffer_seek(buf, buffer_seek_start, offs + _addr); | |
// a string address may be legally 0 under rare cases. | |
if (_addr != 0) _str = buffer_read(buf, buffer_string); | |
buffer_seek(buf, buffer_seek_start, offs + _old); | |
return _str; | |
} | |
function TGINList(buf, offs, castptr) { | |
var _addr = buffer_read(buf, buffer_u32); | |
TGINAssert(_addr != 0, "YY address ptr is 0."); | |
var _old = buffer_tell(buf); | |
buffer_seek(buf, buffer_seek_start, offs + _addr); | |
var _cnt = buffer_read(buf, buffer_u32); | |
var _ret = array_create(_cnt, -1); | |
for (var _i = 0; _i < _cnt; ++_i) { | |
// asset index. | |
var _index = buffer_read(buf, buffer_u32); | |
// cast to ptr() if texture | |
if (is_bool(castptr) && castptr) _index = ptr(_index); | |
_ret[_i] = _index; | |
} | |
buffer_seek(buf, buffer_seek_start, offs + _old); | |
return _ret; | |
} | |
/// @function TGINParse(bufferId) | |
/// @description Parses the TGIN chunk. If any of the variables are undefined, the object should be discarded as invalid. | |
/// @param {buffer} bufferId Buffer index | |
/// @returns {TGINGroup[]} an array of texture group info objects | |
function TGINParse(bufferId) { | |
TGINAssert(is_numeric(bufferId) && buffer_exists(bufferId), "Buffer index is invalid or has been destroyed."); | |
var __found = false; | |
// the buffer pointed by bufferId must have it's tell set at the start of the .win (i.e. FORM) | |
var __winstart = buffer_tell(bufferId); | |
var __winlen = __winstart; | |
// ...and have a valid FORM. If you're RickyG who's using .win obfuscation tools | |
// fuck you! go edit this script if you care. I personally do not support you and won't help you in that case. | |
TGINAssert(buffer_read(bufferId, buffer_u32) == 0x4D524F46, "FORM is invalid."); | |
// length stuff... | |
__winlen = buffer_read(bufferId, buffer_u32); | |
__winlen += 8; // 'FORM' + length itself | |
__winstart += __winstart; | |
var __chunkId = 0, __chunkLen = 0; | |
// while not EOF | |
while (buffer_tell(bufferId) < __winlen) { | |
__chunkId = buffer_read(bufferId, buffer_u32); | |
__chunkLen = buffer_read(bufferId, buffer_u32); | |
// skip it. | |
if (__chunkId != 0x4E494754) { | |
buffer_seek(bufferId, buffer_seek_relative, __chunkLen); | |
continue; | |
} | |
else { | |
__found = true; | |
break; | |
} | |
} | |
TGINAssert(__found == true, "Unable to locate the TGIN chunk."); | |
TGINAssert(buffer_read(bufferId, buffer_u32) == 1, "TGIN chunk version is not one."); | |
var __cnt = buffer_read(bufferId, buffer_u32); | |
var __ret = array_create(__cnt, undefined); | |
for (var __i = 0; __i < __cnt; ++__i) { | |
var __addr = buffer_read(bufferId, buffer_u32); | |
TGINAssert(__addr != 0, "YY object pointer is null."); | |
var __pos = buffer_tell(bufferId); | |
buffer_seek(bufferId, buffer_seek_start, __winstart + __addr); | |
/* read the TGIN item here */ | |
var __o_name = TGINString(bufferId, __winstart); | |
// texture page indicies are "pointers" in GameMaker | |
// so for compatibility reasons we ask TGINList to cast the index to a pointer. | |
var __o_tpag = TGINList(bufferId, __winstart, true); | |
var __o_sprt = TGINList(bufferId, __winstart); | |
var __o_spin = TGINList(bufferId, __winstart); | |
var __o_font = TGINList(bufferId, __winstart); | |
var __o_tile = TGINList(bufferId, __winstart); | |
buffer_seek(bufferId, buffer_seek_start, __winstart + __pos); | |
var __obj = new TGINGroup(__o_name, __o_sprt, __o_spin, __o_font, __o_tile, __o_tpag); | |
__ret[__i] = __obj; | |
} | |
// seek as if we've read an entire .win: | |
buffer_seek(bufferId, buffer_seek_start, __winstart + __winlen); | |
return __ret; | |
} | |
/* | |
var buf; | |
if (parameter_string(1) == "-game") { | |
buf = buffer_load(parameter_string(2)); | |
} | |
else { | |
buf = buffer_load((os_type == os_linux)? "game.unx" : "data.win"); | |
} | |
test = TGINParse(buf); | |
show_debug_message(test); | |
//[ { name : "Default", sprites : [ 0 ], spinesprites : [ ], fonts : [ 0 ], tilesets : [ 0 ], texpages : [ null ] },{ name : "texgroup1", sprites : [ 1 ], spinesprites : [ ], fonts : [ ], tilesets : [ ], texpages : [ 00000001 ] },{ name : "texgroup2", sprites : [ 2 ], spinesprites : [ ], fonts : [ ], tilesets : [ ], texpages : [ 00000002 ] },{ name : "texgroup3", sprites : [ 3 ], spinesprites : [ ], fonts : [ ], tilesets : [ ], texpages : [ 00000003 ] },{ name : "texgroup4", sprites : [ 4 ], spinesprites : [ ], fonts : [ ], tilesets : [ ], texpages : [ 00000004 ] } ] | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment