-
Posts
379 -
Joined
-
Last visited
-
Days Won
11
Content Type
Profiles
Forums
Downloads
Jobs Available
Server Database
Third-Party Services
Top Guides
Store
Crowdfunding
Posts posted by KeyWorld
-
-
Some news today.
Map loading
I really improve my map loading : update the zlib unpacker, optimize the mesh compilation.
It's now about 2-3 times faster than before. It takes ~3 seconds to load a map like Izlude or Prontera, instant loading for little map. Lighthalzen seems to be the slowest to load : ~5 seconds.
I'm quite happy of the result.
Sound objects
I added sound objects to the map, I'm not certain of the volume to use for this objects (Audio API allow a min volume of 0.0 and max volume of 1.0; there are some sound object with a volume of 2.0 so not sure yet what the max volume is here).
You can see the sound visualization of aldebaran (all porings are a sound object):
Lub files
Since Renewal, a big part of servers use lub files to store data info, so it should be normal for robrowser to load this files at runtime to build its DB.
So I wrote a Lub decompiler (PHP, and converted the code to JS), it don't support all opcode but is enough to extract tables (I don't care of extracting functions).
Here the PHP code in action: http://www.robrowser.com/prototype/lub/
For now I'm only able to extract lub version 0x51 but it seems some client use the 0x50 version (why ? ), so I will have to extend the code later.
Sprite Rendering
I re-wrote the whole Entity Manager code, as the old one it support all actions/animations.
I added some setter to update automatically the sprites/act/palettes when modifying/setting a new visual look, ex: you change the sex, it will automaticaly reload all sprites/actions (head, hat, weapon, ...).
Palettes are applying on the pixel shader to avoid having to re-build each sprite image (faster and easier).
I also face the same problem as Shinryo in his topic and used the same way to fix it, but it's definitively not the way to go : collision with roof, weird result when sprite is on the water.
The better way is to project the top vertices to the up vector of the bottom part and modifying UVs to match the new form in the screen, but it's more complicate and I lack knowledge on 3D maths.
Weather
I just add sky and clouds to some maps (yuno, gonryun, thana_boss, 5@tower, ...) using a config file in the DB, it's funny how the client manage it. The result looks good:
Other news
- IE11 will support webgl
- Web API Device Storage will allow to use local GRF without needed to select it each time at runtime (I hope this standard will be accept...).
- Firefox added ASM.js in the latest nighty build. It allow to run some js (at this time just arithmetic code) script at 2 times slower than native speed (comparable as Java and C#), by doing some low typage on variables.
- 5
-
I wrote an online tool some months ago : http://www.robrowser.com/prototype/vdk/ (required a recent browser).
It's not a complete tool (only work with version 1.1 and not sure it work with all vdk files), but if you don't want to install a software in your computer or don't want to extract the whole archive, it do the job.
- 2
-
First thing I see, you add item to a shop "Emistry_shop", I guess you forget to update the shop name (should be "Cloud_Machine").
npcshopadditem "Emistry_Shop",@ItemListscloud[.@i],@ItemCostcloud[.@i];
-
Replace .share_date with .share_date$
The value is truncate because of the conversion to int.
- 1
-
Add a "end;" before "OnHour24:".
-
v - value (string, int or reference)
s - string
i - int
r - reference (variable)
l - label
? - optional parameter
* - as you want optionals parameters
-
It's hardcoded in the executable.
The client now the sprite type using the view id (or the sprite id - since each type is related to a range id) and define for each class the action based on this type.
-
It's not a lossless compression. It's safe.
-
It will be released this year even if it's not totally finished, it will be a good thing to open the source
Same here, I try to do my best to work on this project but sometimes it's hard to manage it and all others things (like my girlfriend lol).
It can be a good thing to have a GRF history/diff/tracking tool to see what Gravity add/remove/change in its files, keep it up ! (I know some others guys had the same idea )
Nice js1k entry, I asked myself "why 'ninja' ?" the first time I saw it, nice done
@project,
No news, have problems with one of my computer, so I will try all I did in "bind mode" (rewrote the whole Entity manager) when I will switch to my girlfriend's home this week end
- 5
-
Feel secured doesn't mean be secured.purchase a SSL certificate and make your server cp secured. plus, seeing a https:// in your website wil make your players feel secured too and wil have confidence in you for keeping their data secured.
Https don't protect from SQL injection and some hacks methods.
Maybe because he doesn't want to cheat but just want to annoyed your server.Surprisingly the hacker only know how to delete the char table, and luckily i got perform daily backup.
As everyone said, it can come from any tool you add to your CP (forum, control panel, bug tracker) or in game npc (check for query_sql) or even from the hoster or your own team.
- 1
-
Yeah I rewrote the whole core as I said before. The old one wasn't really well optimized and organized, and pretty hard to update, now it's much better and user-friendly
About your way to do, it missing some structure at my point of view and will be maybe hard to maintain in future (and it seems you generate the password hash even if not used), but yeah it's fun the way you did it, to merge packet and just define the header to build the correct one.
Hmm maybe I will remove the packet_id from the Network.bindPacket() and move it to the packet structure instead, I don't think we have to care about it at this step...
About js1k yeah it was fun to do lol but very hard to compact to 1024bytes, but I'm really satisfied about the result.
Nice to see you here curiosity
What about your project ?
@Project
Now support 0x200 GRF version with DES encryption.
-
I just add the network core in roBrowser.
I search a way to make it organized and user-friendly to use.
So basically, all packets are converted from http://rathena.org/wiki/index.php?title=Packets using tools/packet-builder/.
Example to parse:
Network.bindPacket( 0x69, PACKET.AC.ACCEPT_LOGIN, function(data){ // data.AuthCode, data.AID, data.userLevel, data.ServerList, ... // do whatever you want with "data" });
Example to send:var pkt = new PACKET.CA.LOGIN(); pkt.ID = "Test"; pkt.Passwd = "Test"; pkt.Version = 20; Network.sendPacket(pkt);
If you have a better idea, let's talk about itThere will be three differents ways to connect to server:
- Using JAVA.
- Using Chrome Socket API.
- Using WebSocket to connect to a Proxy server.
- 1
-
It depend of the OS and graphic card, but yeah for now the canvas should be hardware accelerated.I would really appreciate if you could send me a PM with your advices (If you want to of course ^^)
I think this technology on some browser already use the GPU. I think it does on chrome...
Thanks both of you!
I will drop you a PM, not enough time right now
Keep it up.
-
I'm here just because I see "HTML5" in the title
The result is nice, great work but some things can be change in the code (in my own opinion), it can be good also to check for the support of css3 so you will just use the GPU
-
Read the entire post, or the comments below please.FluxCP Please
- 1
-
Do you really need to modify the model ?
I think just change the texture is enough in your case.
- 1
-
You can integrate it in whatever you want: fluxcp, cerescp, triton, custom CP, or without CP.is this available also to flux?
- 1
-
Why not ?cannot use in flux ? haha
- 1
-
Thank youwow nice Default Theme.
it has adding item in webshop?
As I said in the main post, it's a design integrated to an index.html page. There is no CP in the archive, you are free to integrate it yourself to your favorite one.how to use it
- 1
-
File Name: CeresCP Default Theme
File Submitter: KeyWorld
File Submitted: 26 Feb 2013
File Category: Web Resources
Content Author: KeyWorld
If you remember this topic there was a contest for the upcoming Cerescp default theme.
For now, I don't know if developers stopped to work on the new CeresCP version, but a lot of time passed since the last update/announce and some members asked me to release the default theme I made.
I hope the best to CeresCP developers, the theme can always be used if they continue the project.
So in this archive, an index.html page with css/javascript and images.
Compatible (the last time I checked) with:
- IE6, IE7, IE8, IE9, IE10
- Safari
- Chrome
- Opera
- Firefox
There is no CP in the archive, you will have to integrate it to your favorite one yourself (hey don't pay someone to do it, all the work is already done seriously...).
Have fun
- 5
-
You can find it by reversing the client, or by searching in some source tools as Actor.
But in the past we just have reverse engineering and trying to search by finding redundant informations in the hex.
But your current function is not really good, some bugs on some versions, not really good name convention...
If you want mine:
<?php /** * @fileoverview Action - Loader for the Gravity .act file * @author Vincent Thibault (alias KeyWorld - Twitter: @robrowser) * @version 2.3.0 */ class Action { private $fp, $version; public $actions = array(), $sounds = array(); /// Loader on construct public function __construct($filename=false) { if ( $filename ) $this->open($filename); } /// Open a Action file /// Do some check before. public function open($filename) { if ( substr( $filename, 0, 7 ) !== "data://" ) { if ( ! file_exists($filename) ) throw new Exception("ACT::open() - Can't find file '{$filename}'."); if ( ! is_readable($filename) ) throw new Exception("ACT::open() - Can't read file '{$filename}'."); $this->size = filesize($filename); if ( $this->size < 0x08 ) throw new Exception("ACT::open() - Incorrect file size, shoulnot be a ACT file"); } $this->fp = fopen($filename,'r'); $this->load(); } /// Load an Action file private function load() { extract( unpack( "a2head/C2ver", fread($this->fp, 0x4 ) ) ); if ( $head !== 'AC' ) throw new Exception("ACT::load() - Incorrect act header, is '{$head}' - should be 'AC'"); $this->version = $ver1/10 + $ver2; $this->readActions(); if ( $this->version >= 2.1 ) { // Sound extract( unpack("Vcount", fread( $this->fp, 0x04 ) ) ); for ( $i=0; $i<$count; ++$i ) $this->sounds[$i] = current( unpack('a40', fread( $this->fp, 40 ) ) ); // Delay if ( $this->version >= 2.2 ) foreach( $this->actions as &$action ) $action->delay = current( unpack("f", fread($this->fp, 0x04) ) ) * 25; } } /// Load ACT actions private function readActions() { extract( unpack("vcount/x10", fread( $this->fp, 12 ) ) ); for ( $i=0; $i<$count; ++$i ) { $this->actions[$i] = (object) array( "animations" => $this->readAnimations(), "delay" => 150 ); } } /// Load ACT animations private function readAnimations() { extract( unpack("Vcount", fread( $this->fp, 0x04 ) ) ); $animations = array(); for ( $i=0; $i<$count; ++$i ) { fseek( $this->fp, 32, SEEK_CUR ); $animations[$i] = $this->readLayers(); } return $animations; } /// Load ACT layers private function readLayers() { extract( unpack("Vcount", fread( $this->fp, 0x04 ) ) ); $layers = array(); if ( $this->version < 2.0 ) { $size = 0; $struct = ""; } else if ( $this->version < 2.4 ) { $size = 16; $struct = "C4color/f1scale/Vangle/Vspr_type"; } else if ( $this->version === 2.4 ) { $size = 20; $struct = "C4color/f2scale/Vangle/Vspr_type"; } else { $size = 28; $struct = "C4color/f2scale/Vangle/Vspr_type/Vwidth/Vheight"; } for ( $i=0; $i<$count; ++$i ) { $param = unpack( "Vx/Vy/Vindex/Vis_mirror/" . $struct, fread($this->fp, $size + 16) ); $layers[$i] = (object) array( "pos" => array( $param['x'], $param['y'] ), "index" => $param['index'], "is_mirror" => $param['is_mirror'], "scale" => array( 1.0, 1.0 ), "color" => array( 255, 255, 255, 255 ), "angle" => 0, "spr_type" => 0, "width" => 0, "height" => 0 ); $layer = &$layers[$i]; $layer->color[0] = $param['color1']/255; $layer->color[1] = $param['color2']/255; $layer->color[2] = $param['color3']/255; $layer->color[3] = $param['color4']/255; $layer->scale[0] = isset($param['scale1']) ? $param['scale1'] : 1.0; $layer->scale[1] = isset($param['scale2']) ? $param['scale2'] : $layer->scale[0]; if ( isset($param['angle']) ) $layer->angle = $param['angle']; if ( isset($param['spr_type']) ) $layer->spr_type = $param['spr_type']; if ( isset($param['width']) ) $layer->width = $param['width']; if ( isset($param['height']) ) $layer->height = $param['height']; } $sound = -1; if ( $this->version >= 2.0 ) extract( unpack("Vsound", fread($this->fp,0x04) ) ); $pos= array(); if ( $this->version >= 2.3 ) { extract( unpack("Vcount", fread($this->fp,0x04) ) ); for ( $i=0; $i<$count; ++$i ) { $pos[$i] = (object) unpack( "Vunk/Vx/Vy/Vattr", fread($this->fp,16) ); } } return (object) array( "layers" => $layers, "sound" => $sound, "pos" => $pos ); } /// Compile a ACT file public function compile() { // Header $result = pack('a2C2', 'AC', $this->version * 10 % 10, floor($this->version * 10)/10 ); // Action count $result .= pack( 'vx10', count($this->actions) ); // Compile each actions foreach( $this->actions as $action ) { // Number of animations $result .= pack( 'V', count($action->animations) ); // Compile animations foreach( $action->animations as $animation ) { // 32 uknown offset + layers count $result .= pack( 'x32V', count($animation->layers) ); // Compile layers foreach( $animation->layers as $layer ) { $result .= pack('V4', $layer->pos[0], $layer->pos[1], $layer->index, $layer->is_mirror); if ( $this->version < 2.0 ) continue; else if ( $this->version < 2.4 ) $result .= pack( 'C4fV2', $layer->color[0]*255, $layer->color[1]*255, $layer->color[2]*255, $layer->color[3]*255, $layer->scale[0], $layer->angle, $layer->spr_type ); else if ( $this->version === 2.4 ) $result .= pack( 'C4f2V2', $layer->color[0]*255, $layer->color[1]*255, $layer->color[2]*255, $layer->color[3]*255, $layer->scale[0], $layer->scale[1], $layer->angle, $layer->spr_type ); else $result .= pack( 'C4f2V4', $layer->color[0]*255, $layer->color[1]*255, $layer->color[2]*255, $layer->color[3]*255, $layer->scale[0], $layer->scale[1], $layer->angle, $layer->spr_type, $layer->width, $layer->height ); } // Animation sound if ( $this->version >= 2.0 ) { $result .= pack('V', $animation->sound ); } // Animation imf (head pos) if ( $this->version >= 2.3 ) { $result .= pack('V', count($animation->pos) ); foreach( $animation->pos as $pos ) { $result .= pack( 'V4', $pos->unk, $pos->x, $pos->y, $pos->attr ); } } } } if ( $this->version >= 2.1 ) { // Comple sounds $result .= pack( 'V', count($this->sounds) ); foreach( $this->sounds as $sound ) { $result .= pack( 'a40', $sound ); } // Comple delay if ( $this->version >= 2.2 ) { foreach( $this->actions as $action ) { $result .= pack( 'f', $action->delay / 25 ); } } } return $result; } } ?>
Maybe should I release my character-viewer...Have fun~
-
Well test this:
public function readAct($act,$save,$output,$code) {
// Open the act file.
$this->act = fopen($act, "rb");
// Just like on the sprites we read some infos: ident=ACT, version, number of frames
$this->aHeader = unpack('H4ident/Sversion/SnumFrames', fread($this->act, 0x06));
// Get the filesize (used this for sql database etc.)
$this->aSize = filesize($act);
// The total amount of animations used
$this->aAnimations = $this->aHeader['numFrames'];
// The number of actions is the num of animations divided by 8.
// So what are the "actions"? I just named them like this. They're basicly the directions you can look at. Just like in actOR.
// \ | / }
// -- o -- }-> 8 in total
// / | \ }
$this->aActions = ($this->aAnimations / 8);
// The version
$this->aVersion = dechex($this->aHeader['version']);
// Format the version nicely
$this->aVersion = (double)preg_replace('{([0-9])(.*?)([0-9])}', '$1.$2', $this->aVersion);
// Skip some useless data on one needs
fseek($this->act, 0xA, SEEK_CUR);
// We're currently at action 0
$currentAction = 0;
// Our index for the while loop
$anim = 0;
// Arrays we save our informations in
$pointerMemoryANIM = array();
$pointerMemoryNF = array();
$pointerMemoryPAT = array();
// Lets go through the animations, shall we?
while($anim < $this->aAnimations) {
// First how many Frames does the action have?
// On a normal headgear this would be 3. Because when you are sitting downwards you can look down with your head, left and right. So 3 in total.
// Ff you have an animated sprite its more obviously
$this->aAnimData[$anim] = unpack('lnumFrames', fread($this->act, 0x04));
// So lets loop through those Frames, cuz they all got individual informations for us
for($nf = 0; $nf < $this->aAnimData[$anim]['numFrames']; $nf++) {
// Skip useless data
fseek($this->act, 0x20, SEEK_CUR);
// And now we check how many subFrames this frame got. Or better said Patterns (like in actOR)
// For example, if you have a monster sprite and some special effects as seperates sprite frames in the .spr file.
// You'll have to paste them onto the stage right? Thats where the patters are being created. Like layers in photoshop.
$this->aAnimData[$anim][$nf] = unpack('lnumSubFrames', fread($this->act, 0x04));
// Loop through the patterns or layers for more info about them
for($patNo = 0; $patNo < $this->aAnimData[$anim][$nf]['numSubFrames']; $patNo++) {
$this->aAnimData[$anim][$nf][$patNo] = unpack('lxOffset/lyOffset/lsprNo/lmirrored/Cred/Cgreen/Cblue/Calpha', fread($this->act, 0x14));
if($this->aVersion < 2.0 );
else if($this->aVersion < 2.4 ) $this->aAnimData[$anim][$nf][$patNo] += unpack('fxyScale/lrotation/lsprType', fread($this->act, 12));
else if($this->aVersion == 2.4 ) $this->aAnimData[$anim][$nf][$patNo] += unpack('fxScale/fyScale/lrotation/lspr_type', fread($this->act, 16));
else $this->aAnimData[$anim][$nf][$patNo] += unpack('fxScale/fyScale/lrotation/lsprType/lsprWidth/lsprHeight', fread($this->act, 24));
}
// The end of the Patterns/Layers on the Frame.
// So lets see if it has some kind of sound attached to it? (To the frame)
fseek( $this->act, 4, SEEK_CUR ); // sound id, store it in a variable if you want
extract( unpack("lnumExtraInfo", fread($this->act,0x04) ) );
$extraInfos = array();
for ( $i=0; $i<$numExtraInfo; ++$i ) {
$extraInfos[$i] = unpack( "x4/VExtXOffsetX/VExtXOffsetY/x4", fread($this->act,16) );
}
}
// Increase our Action and loop through the next frames and patterns^^
$anim++;
}
// After reading all infos we are at the end of the act file where the sound informations are stored.
$this->aSoundData = unpack('lnumSounds', fread($this->act, 0x04));
// It has some sounds?
if($this->aSoundData['numSounds'] > 0) {
// We loop through number of sounds to grab it.
for($nSnd = 0; $nSnd < $this->aSoundData['numSounds']; $nSnd++) {
// Now because the sound file is a string (directs to some .wav file in the grf), saved in hex and for our advantage always exactly 40 bytes long
// we read the string as hex values and save it like that
$this->aSoundData[$nSnd] = unpack('H80file', fread($this->act, 0x28));
}
}
// Oh we also got the interval a frame is played at? That info is ours! >
for($intv = 0; $intv < $this->aAnimations; $intv++) {
$this->aAnimData[$intv] += unpack('fanimSpeed', fread($this->act, 0x04));
}
// Lets format our earlier saved hex string to a actual string with letters and not just numbers ^^
// Some note: If there are sounds in the act (mostly monsters) there always appears to be a sound called "atk", just like that.
// It doesnt exist in the grf and I have no idea how it is being handled. Maybe some description of the sounds?
foreach($this->aSoundData as $id=>$string) {
if((string)$id != 'numSounds')
$this->aSoundData[$id] = str_replace(pack('H2','00'),"",(pack('H*', $string['file'])));
}
// Lets display our results of the act file.
$act = '$jact';
if (strpos($output, "head")) {
$act = '$hact';
}
else {
echo '<pre>';
echo print_r($this->aAnimData, true);
echo print_r($this->aSoundData, true);
echo '</pre>';
}
// Close the file, its no longer needed. =(
fclose($this->act);
}
- 1
-
Oups the latest thing I wrote was wrong:
fseek( $this->act, 4, SEEK_CUR ); // sound id, store it in a variable if you want
extract( unpack("lnumExtraInfo", fread($this->act,0x04) ) );
$extraInfos = array();
for ( $i=0; $i<$numExtraInfo; ++$i ) {
$extraInfos[$i] = unpack( "x2/VExtXOffsetX/VExtXOffsetY/x2", fread($this->act,10) );
}
Now working. -
Did you even read what I wrote ?
If you want to store extrainfo, you have to do this:fseek( $this->act, 4, SEEK_CUR ); // sound id, store it in a variable if you want
$extrainfo = unpack('lbool', fread($this->act, 0x04));// Extras infos (if you need)
fseek($this->act, 0x10 * $extrainfo['bool'], SEEK_CUR);
fseek( $this->act, 4, SEEK_CUR ); // sound id, store it in a variable if you want extract( unpack("lnumExtraInfo", fread($this->fp,0x04) ) ); $extraInfos = array(); for ( $i=0; $i<$numExtraInfo; ++$i ) { $extraInfos[$i] = unpack( "x4/VExtXOffsetX/VExtXOffsetY/x4", fread($this->act,16) ); }
Edit: Why the bbcode is buggy ?
server time at website different with server time in game
in Web Support
Posted
You can use the PHP function date_default_timezone_set().
I can't help you muh since you don't give any information of your website (language, panel, etc.).