open-tibia-tools 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +29 -0
  2. package/effectFramesGenerator.html +42 -0
  3. package/effectFramesGenerator.ts +95 -0
  4. package/itemImageFramesGenerator.html +45 -0
  5. package/itemImageFramesGenerator.ts +140 -0
  6. package/itemImageGenerator.html +40 -0
  7. package/itemImageGenerator.ts +161 -0
  8. package/missileFramesGenerator.html +42 -0
  9. package/missileFramesGenerator.ts +95 -0
  10. package/otbEditor.html +21 -0
  11. package/otbEditor.ts +106 -0
  12. package/outfitImageGenerator.html +38 -0
  13. package/outfitImageGenerator.ts +109 -0
  14. package/outfitImagePhpGeneratorCode.ts +19 -0
  15. package/package.json +28 -0
  16. package/tests.html +29 -0
  17. package/tests.ts +218 -0
  18. package/tools/colored-outfit-images-generator/README.md +7 -0
  19. package/tools/colored-outfit-images-generator/abuse_warning.png +0 -0
  20. package/tools/colored-outfit-images-generator/animoutfit.php +103 -0
  21. package/tools/colored-outfit-images-generator/cacheGenerator.php +40 -0
  22. package/tools/colored-outfit-images-generator/config.php +25 -0
  23. package/tools/colored-outfit-images-generator/filesAsJson.php +22 -0
  24. package/tools/colored-outfit-images-generator/index.php +21 -0
  25. package/tools/colored-outfit-images-generator/libs/gifCreator.php +343 -0
  26. package/tools/colored-outfit-images-generator/libs/outfitter.php +312 -0
  27. package/tools/colored-outfit-images-generator/outfit.php +77 -0
  28. package/tools/colored-outfit-images-generator/release.php +40 -0
  29. package/tools/item-image-frames-to-animated-gif-converter/1-10/1.gif +0 -0
  30. package/tools/item-image-frames-to-animated-gif-converter/1-10/1.png +0 -0
  31. package/tools/item-image-frames-to-animated-gif-converter/1-10/10.gif +0 -0
  32. package/tools/item-image-frames-to-animated-gif-converter/1-10/10.png +0 -0
  33. package/tools/item-image-frames-to-animated-gif-converter/1-10/2.gif +0 -0
  34. package/tools/item-image-frames-to-animated-gif-converter/1-10/2.png +0 -0
  35. package/tools/item-image-frames-to-animated-gif-converter/1-10/3.gif +0 -0
  36. package/tools/item-image-frames-to-animated-gif-converter/1-10/3.png +0 -0
  37. package/tools/item-image-frames-to-animated-gif-converter/1-10/4.gif +0 -0
  38. package/tools/item-image-frames-to-animated-gif-converter/1-10/4.png +0 -0
  39. package/tools/item-image-frames-to-animated-gif-converter/1-10/5.gif +0 -0
  40. package/tools/item-image-frames-to-animated-gif-converter/1-10/5.png +0 -0
  41. package/tools/item-image-frames-to-animated-gif-converter/1-10/6.gif +0 -0
  42. package/tools/item-image-frames-to-animated-gif-converter/1-10/6.png +0 -0
  43. package/tools/item-image-frames-to-animated-gif-converter/1-10/7.gif +0 -0
  44. package/tools/item-image-frames-to-animated-gif-converter/1-10/7.png +0 -0
  45. package/tools/item-image-frames-to-animated-gif-converter/1-10/8.gif +0 -0
  46. package/tools/item-image-frames-to-animated-gif-converter/1-10/8.png +0 -0
  47. package/tools/item-image-frames-to-animated-gif-converter/1-10/9.gif +0 -0
  48. package/tools/item-image-frames-to-animated-gif-converter/1-10/9.png +0 -0
  49. package/tools/item-image-frames-to-animated-gif-converter/README.md +20 -0
  50. package/tools/item-image-frames-to-animated-gif-converter/cli_convert.php +42 -0
  51. package/tools/item-image-frames-to-animated-gif-converter/generated-zip-archives/.gitignore +3 -0
  52. package/tools/item-image-frames-to-animated-gif-converter/generated-zip-archives/index.html +1 -0
  53. package/tools/item-image-frames-to-animated-gif-converter/index.php +97 -0
  54. package/tools/item-image-frames-to-animated-gif-converter/lib/abstractPngConverterAnimation.php +87 -0
  55. package/tools/item-image-frames-to-animated-gif-converter/lib/apngCreator.php +247 -0
  56. package/tools/item-image-frames-to-animated-gif-converter/lib/converterPngToApngAnimation.php +93 -0
  57. package/tools/item-image-frames-to-animated-gif-converter/lib/converterPngToGifAnimation.php +90 -0
  58. package/tools/item-image-frames-to-animated-gif-converter/lib/gifCreator.php +339 -0
  59. package/tsconfig.json +12 -0
  60. package/webpack.config.js +53 -0
  61. package/websiteImageGeneratorBase.ts +156 -0
package/tests.ts ADDED
@@ -0,0 +1,218 @@
1
+ import {
2
+ Client,
3
+ DatManager,
4
+ FrameGroupType,
5
+ ImageGenerator,
6
+ InputFile,
7
+ OtbManager,
8
+ Point,
9
+ Size,
10
+ Sprite,
11
+ SpriteManager
12
+ } from "@gesior/open-tibia-library";
13
+
14
+ function inputFileFromUrl(url: string): Promise<InputFile> {
15
+ return new Promise(function (resolve, reject) {
16
+ const xhr = new XMLHttpRequest();
17
+ xhr.responseType = "arraybuffer";
18
+ xhr.onload = function () {
19
+ if (this.status >= 200 && this.status < 300) {
20
+ resolve(InputFile.fromUint8Array(new Uint8Array(this.response)));
21
+ } else {
22
+ reject("Response status: " + this.status);
23
+ }
24
+ };
25
+ xhr.onerror = function (e) {
26
+ reject(e);
27
+ };
28
+ xhr.open("GET", url, true);
29
+ xhr.send();
30
+ });
31
+ }
32
+
33
+ const canvas = <HTMLCanvasElement>document.getElementById('view');
34
+ const ctx = canvas.getContext("2d");
35
+
36
+ function drawImage(sprite: Sprite, x, y) {
37
+ const palette = ctx.getImageData(x, y, sprite.getWidth(), sprite.getHeight());
38
+ palette.data.set(new Uint8ClampedArray(sprite.getPixels().m_buffer.buffer));
39
+ ctx.putImageData(palette, x, y);
40
+ }
41
+
42
+ async function testGenerateAllItemImages() {
43
+ const client = new Client();
44
+ client.setClientVersion(1076);
45
+
46
+ const serverUrl = 'http://127.0.0.1/1076/';
47
+
48
+ const datManager = new DatManager(client);
49
+ console.log('loaded dat', datManager.loadDat(await inputFileFromUrl(serverUrl + 'Tibia.dat')));
50
+
51
+ const otbManager = new OtbManager(client);
52
+ console.log('loaded otb', otbManager.loadOtb(await inputFileFromUrl(serverUrl + 'items.otb')));
53
+
54
+ const spriteManager = new SpriteManager(client);
55
+ console.log('loaded spr', spriteManager.loadSpr(await inputFileFromUrl(serverUrl + 'Tibia.spr')));
56
+
57
+ }
58
+
59
+ async function testLoadFromUrlsAndDrawImage() {
60
+ const client = new Client();
61
+ client.setClientVersion(1076);
62
+
63
+ const serverUrl = 'http://127.0.0.1/1076/';
64
+
65
+ const datManager = new DatManager(client);
66
+ console.log('loaded dat', datManager.loadDat(await inputFileFromUrl(serverUrl + 'Tibia.dat')));
67
+
68
+ const otbManager = new OtbManager(client);
69
+ console.log('loaded otb', otbManager.loadOtb(await inputFileFromUrl(serverUrl + 'items.otb')));
70
+
71
+ const spriteManager = new SpriteManager(client);
72
+ console.log('loaded spr', spriteManager.loadSpr(await inputFileFromUrl(serverUrl + 'Tibia.spr')));
73
+
74
+ // get client ID of item 2400 (magic sword in items.xml)
75
+ let magicSwordClientId = otbManager.getItem(2400).getClientId();
76
+ // get data from '.dat' about that item
77
+ let magicSwordThingType = datManager.getItem(magicSwordClientId);
78
+ // get first sprite [image] of that item
79
+ let firstMagicSwordSprite = magicSwordThingType.getFrameGroup(FrameGroupType.FrameGroupIdle).getSprite(0);
80
+ // get image from .spr file
81
+ let firstImagePixelsData = spriteManager.getSprite(firstMagicSwordSprite);
82
+ // draw image in webbrowser with Canvas on position 0, 0
83
+ drawImage(firstImagePixelsData, 0, 0);
84
+
85
+ const itemid = 2400;
86
+ const imageGenerator = new ImageGenerator(datManager, spriteManager, otbManager);
87
+ const itemSprite = imageGenerator.generateItemImageByServerId(itemid);
88
+
89
+ drawImage(itemSprite, 32, 0);
90
+ const sprite = new Sprite(new Size(64, 64));
91
+ sprite.blit(new Point(32, 32), firstImagePixelsData);
92
+ drawImage(sprite, 0, 0);
93
+
94
+ // export to global scope for debuging
95
+ window['d'] = {
96
+ client: client,
97
+ datManager: datManager,
98
+ otbManager: otbManager,
99
+ spriteManager: spriteManager
100
+ };
101
+
102
+
103
+ // let otbFile = otbManager.saveOtb();
104
+ // let a = document.createElement('a');
105
+ // let url = window.URL.createObjectURL(new Blob(new Array(otbFile.getUint8Array())));
106
+ // a.href = url;
107
+ // a.download = 'items.otb';
108
+ // a.click();
109
+ // window.URL.revokeObjectURL(url);
110
+ // a.remove();
111
+
112
+ // console.log('Generated dat file', datManager.saveDat());
113
+ // console.log('Generated otb file', otbManager.saveOtb());
114
+ // console.log('Generated spr file', spriteManager.saveSpr());
115
+ console.log('All data loaded. You can access it by variable "d".')
116
+ }
117
+
118
+ async function testFilePicker() {
119
+ const clientVersionInput = <HTMLInputElement>document.getElementById('clientversion');
120
+ const sprPicker = <HTMLInputElement>document.getElementById('spr');
121
+ const datPicker = <HTMLInputElement>document.getElementById('dat');
122
+ const otbPicker = <HTMLInputElement>document.getElementById('otb');
123
+ const itemIdInput = <HTMLInputElement>document.getElementById('itemid');
124
+
125
+ let client: Client;
126
+ let sprManager: SpriteManager;
127
+ let datManager: DatManager;
128
+ let otbManager: OtbManager;
129
+
130
+ let sprLoaded = false;
131
+ let datLoaded = false;
132
+ let otbLoaded = false;
133
+
134
+ function updateItemView(itemid) {
135
+ console.log(sprLoaded, datLoaded, otbLoaded, client, itemid, sprManager, datManager, otbManager);
136
+ if (sprLoaded && datLoaded && otbLoaded) {
137
+ try {
138
+ let magicSwordClientId = otbManager.getItem(itemid).getClientId();
139
+ let magicSwordThingType = datManager.getItem(magicSwordClientId);
140
+ let firstMagicSwordSprite = magicSwordThingType.getFrameGroup(FrameGroupType.FrameGroupIdle).getSprite(0);
141
+ let firstImagePixelsData = sprManager.getSprite(firstMagicSwordSprite);
142
+ drawImage(firstImagePixelsData, 0, 0);
143
+
144
+ } catch (e) {
145
+ console.error(e);
146
+ }
147
+ }
148
+ }
149
+
150
+ clientVersionInput.onchange = function (event) {
151
+ let clientVersion = parseInt(clientVersionInput.value);
152
+ client = new Client();
153
+ client.setClientVersion(clientVersion);
154
+ sprPicker.onchange(null);
155
+ datPicker.onchange(null);
156
+ otbPicker.onchange(null);
157
+ updateItemView(parseInt(itemIdInput.value));
158
+ };
159
+
160
+ sprPicker.onchange = function (event) {
161
+ if (sprPicker.files.length > 0) {
162
+ sprLoaded = false;
163
+ sprManager = new SpriteManager(client);
164
+ const file = sprPicker.files[0];
165
+ var reader = new FileReader();
166
+ reader.readAsArrayBuffer(file);
167
+ reader.onload = function (event: any) {
168
+ sprLoaded = sprManager.loadSpr(InputFile.fromUint8Array(new Uint8Array(event.target.result)));
169
+ }
170
+ }
171
+ };
172
+
173
+ datPicker.onchange = function (event) {
174
+ if (datPicker.files.length > 0) {
175
+ datLoaded = false;
176
+ datManager = new DatManager(client);
177
+ const file = datPicker.files[0];
178
+ var reader = new FileReader();
179
+ reader.readAsArrayBuffer(file);
180
+ reader.onload = function (event: any) {
181
+ datLoaded = datManager.loadDat(InputFile.fromUint8Array(new Uint8Array(event.target.result)));
182
+ }
183
+ }
184
+ };
185
+
186
+ otbPicker.onchange = function (event) {
187
+ if (otbPicker.files.length > 0) {
188
+ otbLoaded = false;
189
+ otbManager = new OtbManager(client);
190
+ const file = otbPicker.files[0];
191
+ var reader = new FileReader();
192
+ reader.readAsArrayBuffer(file);
193
+ reader.onload = function (event: any) {
194
+ otbLoaded = otbManager.loadOtb(InputFile.fromUint8Array(new Uint8Array(event.target.result)));
195
+ }
196
+ }
197
+ };
198
+
199
+ itemIdInput.onchange = function (event) {
200
+ updateItemView(parseInt(itemIdInput.value));
201
+ };
202
+ }
203
+
204
+ // testGenerateAllItemImages();
205
+ testLoadFromUrlsAndDrawImage();
206
+ // testFilePicker();
207
+ /*
208
+ download OTB:
209
+
210
+ otbFile = otbManager.saveOtb();
211
+ a = document.createElement('a');
212
+ url = window.URL.createObjectURL(new Blob(new Array(otbFile.getUint8Array())));
213
+ a.href = url;
214
+ a.download = 'items.otb';
215
+ a.click();
216
+ window.URL.revokeObjectURL(url);
217
+ a.remove();
218
+ */
@@ -0,0 +1,7 @@
1
+ ## Colored outfit images generator
2
+
3
+ In this folder are PHP files to generate colored outfit images from outfit images exported by `outfitImageGenerator.html`.
4
+
5
+ Set write file permissions to unzipped folder for PHP. It will generate cache files in folders with images on the first run.
6
+
7
+ You can generate `outfits.zip` using official host of OpenTibiaLibrary: https://outfit-images.ots.me/generator/
@@ -0,0 +1,103 @@
1
+ <?php
2
+
3
+ require_once('./config.php');
4
+
5
+ if (!file_exists('./cache.generated.txt')) {
6
+ require_once('./cacheGenerator.php');
7
+ exit;
8
+ }
9
+
10
+ header('Cache-control: max-age=' . (60 * 60 * 24 * 365));
11
+ header('Expires: ' . gmdate(DATE_RFC1123, time() + 60 * 60 * 24 * 365));
12
+ header('Last-Modified: ' . gmdate('D, d M Y H:i:s', 1337) . ' GMT');
13
+ if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
14
+ header('HTTP/1.0 304 Not Modified');
15
+ header('Cache-Control: public');
16
+ header('Pragma: cache');
17
+ exit;
18
+ }
19
+
20
+ // Block sites that hotlink your host and overload it
21
+ $abusersList = array('aurera-global.com', 'bad-server.com');
22
+ if (isset($_SERVER['HTTP_REFERER']) && (in_array(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST), $abusersList) ||
23
+ in_array(substr(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST), 4), $abusersList))
24
+ ) {
25
+ header('Content-Type: image/png');
26
+ readfile('abuse_warning.png');
27
+ exit;
28
+ }
29
+
30
+ require('libs/outfitter.php');
31
+ require('libs/gifCreator.php');
32
+
33
+ Outfitter::$outfitPath = $outfitImagesPath;
34
+ Outfitter::setResizeAllOutfitsTo64px($resizeAllOutfitsTo64px);
35
+
36
+ $id = 0;
37
+ if (isset($_GET['id'])) {
38
+ $id = (int)$_GET['id'];
39
+ }
40
+ if (!Outfitter::loadData($id, false)) {
41
+ exit('Outfit does not exist or file cache is not generated.');
42
+ }
43
+
44
+ $mount = 0;
45
+ if (isset($_GET['mount'])) {
46
+ $mount = (int)$_GET['mount'];
47
+ }
48
+ if ($mount > 0 && !Outfitter::loadData($mount, true)) {
49
+ exit('Mount outfit does not exist or file cache is not generated.');
50
+ }
51
+
52
+ $head = 0;
53
+ if (isset($_GET['head'])) {
54
+ $head = (int)$_GET['head'];
55
+ }
56
+ $body = 0;
57
+ if (isset($_GET['body'])) {
58
+ $body = (int)$_GET['body'];
59
+ }
60
+ $legs = 0;
61
+ if (isset($_GET['legs'])) {
62
+ $legs = (int)$_GET['legs'];
63
+ }
64
+ $feet = 0;
65
+ if (isset($_GET['feet'])) {
66
+ $feet = (int)$_GET['feet'];
67
+ }
68
+ $addons = 0;
69
+ if (isset($_GET['addons'])) {
70
+ $addons = (int)$_GET['addons'];
71
+ }
72
+ $direction = 3;
73
+ if (isset($_GET['direction'])) {
74
+ $direction = (int)$_GET['direction'];
75
+ }
76
+
77
+ $frames = [];
78
+ $durations = [];
79
+
80
+ $moveAnimFrames = Outfitter::getOutfitFramesNumber();
81
+
82
+ // rotate player, BIG IMAGES, 20-80 KB per outfit!
83
+ //for($direction = 1; $direction <= 4; $direction++)
84
+ for ($moveAnimFrame = 1; $moveAnimFrame <= $moveAnimFrames; ++$moveAnimFrame) {
85
+ $frames[] = Outfitter::instance()->outfit(
86
+ $id,
87
+ $addons,
88
+ $head,
89
+ $body,
90
+ $legs,
91
+ $feet,
92
+ $mount,
93
+ $direction,
94
+ $moveAnimFrame
95
+ );
96
+ $durations[] = $walkSpeeds[$moveAnimFrames];
97
+ }
98
+ $gc = new GifCreator();
99
+ $gc->create($frames, $durations, 0);
100
+ $gifBinary = $gc->getGif();
101
+
102
+ header('Content-type: image/gif');
103
+ echo $gifBinary;
@@ -0,0 +1,40 @@
1
+ <?php
2
+
3
+ require_once('./config.php');
4
+
5
+ $dirIterator = new RecursiveDirectoryIterator($outfitImagesPath, FilesystemIterator::UNIX_PATHS);
6
+ $iterator = new RecursiveIteratorIterator($dirIterator, RecursiveIteratorIterator::SELF_FIRST);
7
+
8
+ $outfits = [];
9
+ $i = 0;
10
+ foreach ($iterator as $file)
11
+ {
12
+ if ($file->isFile())
13
+ {
14
+ $filePath = trim($file->getPath(), '.');
15
+ $filePath = trim($filePath, '/');
16
+ $outfitIdData = explode('/', $filePath);
17
+ $outfitId = $outfitIdData[1];
18
+ $outfits[$outfitId]['files'][] = $filePath . '/' . $file->getFilename();
19
+ if(isset($outfits[$outfitId]['framesNumber']))
20
+ $outfits[$outfitId]['framesNumber'] = max($outfits[$outfitId]['framesNumber'], (int) substr($file->getFilename(), 0, 1));
21
+ else
22
+ $outfits[$outfitId]['framesNumber'] = (int) substr($file->getFilename(), 0, 1);
23
+ }
24
+ }
25
+
26
+ // CODE TO CHECK WHAT VALUES OF 'framesNumber' ARE POSSIBLE FOR YOUR OUTFITS
27
+ $frameNumbers = [0,0,0,0,0,0,0,0,0,0];
28
+ foreach($outfits as $outfitId => $outfit)
29
+ {
30
+ if (!file_put_contents($outfitImagesPath . '/' . $outfitId . '/outfit.data.txt', serialize($outfit))) {
31
+ exit('PHP cannot write to: "' . $outfitImagesPath . '/' . $outfitId . '/outfit.data.txt", check directory access rights');
32
+ }
33
+ $frameNumbers[$outfit['framesNumber']]++;
34
+ }
35
+
36
+ if (!file_put_contents('./cache.generated.txt', 'cache generated')) {
37
+ exit('PHP cannot write to: "./cache.generated.txt", check directory access rights');
38
+ }
39
+ echo 'FILE SYSTEM CACHE GENERATED<br />Animation frames count in loaded outfits:';
40
+ var_dump($frameNumbers);
@@ -0,0 +1,25 @@
1
+ <?php
2
+
3
+ $outfitImagesPath = './outfits_anim/';
4
+ // resize all outfits to 64x64 pixels, place smaller outfits in bottom-right corner
5
+ $resizeAllOutfitsTo64px = true;
6
+
7
+ // animation speeds: number of animation frames => time in 0.01 of second
8
+ $walkSpeeds = [
9
+ 1 => 50,
10
+ 2 => 35,
11
+ 3 => 30,
12
+ 4 => 15,
13
+ 5 => 15,
14
+ 6 => 15,
15
+ 7 => 15,
16
+ 8 => 10,
17
+ 9 => 8
18
+ ];
19
+
20
+ /*
21
+ some server configurations may print warnings from graphics library
22
+ these warnings are interpreted as part of image and make image unreadable for web browsers
23
+ if you get black/empty image, you can try to uncomment line below to disable all warnings
24
+ */
25
+ // error_reporting(0);
@@ -0,0 +1,22 @@
1
+ <?php
2
+
3
+ // Code to generate 'colored-outfit-images-generator' files as JSON object of base64 strings for 'outfitImagePhpGeneratorCode.ts'
4
+
5
+ $filesList = [
6
+ 'libs/gifCreator.php',
7
+ 'libs/outfitter.php',
8
+ 'abuse_warning.png',
9
+ 'animoutfit.php',
10
+ 'cacheGenerator.php',
11
+ 'config.php',
12
+ 'index.php',
13
+ 'outfit.php'
14
+ ];
15
+
16
+ $filesContent = [];
17
+
18
+ foreach ($filesList as $file) {
19
+ $filesContent[$file] = base64_encode(file_get_contents($file));
20
+ }
21
+
22
+ echo json_encode($filesContent, JSON_PRETTY_PRINT);
@@ -0,0 +1,21 @@
1
+ <html lang="en">
2
+ <head>
3
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4
+ <title>Tibia Outfit Images Generator 0.2.1</title>
5
+ </head>
6
+ <body>
7
+ <span style="font-size:20px">
8
+ This is index file.<br/>
9
+ Open <b>animoutfit.php</b> with valid parameters to generate animated outfit image. For example:<br/>
10
+ <a href="animoutfit.php?id=128&addons=3&head=123&body=12&legs=23&feet=31&mount=0&direction=2">
11
+ animoutfit.php?id=128&addons=3&head=123&body=12&legs=23&feet=31&mount=0&direction=2
12
+ </a><br/>
13
+ <br/>
14
+ Open <b>outfit.php</b> with valid parameters to generate static outfit image. For example:<br/>
15
+ <a href="outfit.php?id=128&addons=3&head=123&body=12&legs=23&feet=31&mount=0&direction=2">
16
+ outfit.php?id=128&addons=3&head=123&body=12&legs=23&feet=31&mount=0&direction=2
17
+ </a><br/>
18
+ </span>
19
+ </body>
20
+ </head>
21
+ </html>