-
Content Count
6 -
Joined
-
Last visited
-
Days Won
1
Content Type
Profiles
Forums
Downloads
Staff Applications
Calendar
Everything posted by AcidMarco
-
Guild emblems on Flux CP after HTTP release
AcidMarco replied to Timokha's question in Website Support
Some time ago I adjusted the emblem display on the website, but I don't remember which file I modified. I think it was related to the imagecreatefrombmpstring function, but I could be wrong - it wasn't too difficult to fix it. Below I'm sending potential files that may have been changed, compare them with your own files. Also, pay attention to the PHP error logs - often the solution lies there. \lib\Flux\EmblemExporter.php <?php require_once 'functions/imagecreatefrombmpstring.php'; /** * */ class Flux_EmblemExporter { /** * */ public $loginAthenaGroup; /** * */ public $athenaServers = array(); /** * */ public function __construct(Flux_LoginAthenaGroup $loginAthenaGroup) { $this->loginAthenaGroup = $loginAthenaGroup; } /** * */ public function addAthenaServer(Flux_Athena $athenaServer) { if (!in_array($athenaServer, $this->loginAthenaGroup->athenaServers, true)) { throw new Flux_Error( "{$athenaServer->serverName} is not a valid char/map server defined in the {$this->loginAthenaGroup->serverName} group."); } $this->athenaServers[$athenaServer->serverName] = $athenaServer; } /** * */ public function exportArchive() { $topDir = $this->sanitizePathName($this->loginAthenaGroup->serverName); $tmpDir = FLUX_DATA_DIR.'/tmp'; $tmpFile = tempnam($tmpDir, 'zip'); // Create zip archive. $zip = new ZipArchive(); $zip->open($tmpFile, ZIPARCHIVE::OVERWRITE); $zip->addEmptyDir($topDir); foreach ($this->athenaServers as $athenaServer) { $athenaDir = $this->sanitizePathName($athenaServer->serverName); $zip->addEmptyDir("$topDir/$athenaDir"); $sql = "SELECT name, emblem_data FROM {$athenaServer->charMapDatabase}.guild WHERE emblem_len > 0 ORDER BY name ASC"; $sth = $athenaServer->connection->getStatement($sql); $sth->execute(); $guilds = $sth->fetchAll(); if ($guilds) { foreach ($guilds as $guild) { $emblemData = @gzuncompress(pack('H*', $guild->emblem_data)); $emblemImage = imagecreatefrombmpstring($emblemData); ob_start(); imagepng($emblemImage); $data = ob_get_clean(); $emblemName = sprintf('%s.png', $this->sanitizePathName($guild->name)); $zip->addFromString("$topDir/$athenaDir/$emblemName", $data); } } } // Close archive. $zip->close(); // Send out appropriate HTTP headers. $filename = urlencode(sprintf('%s-%s-emblems.zip', strtolower($topDir), date('Ymd'))); header('Content-Type: application/zip'); header('Content-Length: '.filesize($tmpFile)); header("Content-Disposition: attachment; filename=$filename"); // Read contents of the file. readfile($tmpFile); // Remove temporary file. unlink($tmpFile); exit; } /** * */ private function sanitizePathName($pathName) { return preg_replace('/[^\w\d ]+/', '', $pathName); } } ?> \lib\functions\imagecreatefrombmpstring.php <?php /** * Convert a bmp string to Image resource * @param {string} $data - BMP string content * @return {resource} image resource */ function imagecreatefrombmpstring($data) { // Read header extract( unpack("a2signature/x8/Voffset/x4/Vwidth/Vheight/x2/vbits", substr($data, 0, 30))); if ($signature !== 'BM') { return false; } // Create image $img = imagecreatetruecolor($width, $height); imagealphablending($img, false); imagesavealpha($img, true); // Load palette (if used) $paletteSize = $offset - 54; $imagePalette = array(); if ($paletteSize > 0 && $bits < 16) { $palette = unpack('C'. $paletteSize, substr($data, 54, $paletteSize)); for ($i = 1, $p = 0; $i < $paletteSize; $i += 4, $p++ ) { $b = $palette[$i+0]; $g = $palette[$i+1]; $r = $palette[$i+2]; $a = $palette[$i+3]; // Magenta is transparent. if (($r & 0xf8 === 0xf8) && ($g === 0) && ($b & 0xf8 === 0xf8)) { $a = 127; } $imagePalette[$p] = imagecolorallocatealpha($img, $r, $g, $b, $a); } } // Read ImageData $skip = ( 4 - ( (( ($bits * $width) + 7) >> 3 ) & 3 ) ) % 4; $size = $width * $height * ($bits >> 3) + $skip * $height; $imageData = unpack('C'. $size, substr($data, $offset, $size) ); switch ($bits) { // Not an original DIB file ? default: return false; // 24 bits BMP case 24: for ($i = 1, $y = $height-1; $y > -1; $y--, $i += $skip) { for ($x = 0; $x < $width; $x++, $i+=3) { $b = $imageData[$i+0]; $g = $imageData[$i+1]; $r = $imageData[$i+2]; if ($r === 255 && $g === 0 && $b === 255) { $c = imagecolorallocatealpha($img, $r, $g, $b, 127); } else { $c = imagecolorallocate($img, $r, $g, $b); } imagesetpixel($img, $x, $y, $c ); } } break; // 8 bits BMP case 8: for ($i = 1, $y = $height-1; $y > -1; $y--, $i += $skip) { for ($x = 0; $x < $width; $x++, $i++) { imagesetpixel($img, $x, $y, $imagePalette[$imageData[$i]] ); } } break; // 4 bits BMP case 4: for ($i = 1, $y = $height-1; $y > -1; $y--, $i += $skip) { for ($x = 0; $x < $width; $x+=2, $i++) { $byte = &$imageData[$i]; imagesetpixel($img, $x+0, $y, $imagePalette[$byte >> 4 ]); imagesetpixel($img, $x+1, $y, $imagePalette[$byte & 0x0F]); } } break; // 1 bit BMP case 1: for ($i = 1, $y = $height-1; $y > -1; $y--, $i += $skip) { for ($x = 0; $x < $width; $x+=8, $i++) { $byte = &$imageData[$i]; imagesetpixel($img, $x+0, $y, $imagePalette[ !!($byte & 0x80) ]); imagesetpixel($img, $x+1, $y, $imagePalette[ !!($byte & 0x40) ]); imagesetpixel($img, $x+2, $y, $imagePalette[ !!($byte & 0x20) ]); imagesetpixel($img, $x+3, $y, $imagePalette[ !!($byte & 0x10) ]); imagesetpixel($img, $x+4, $y, $imagePalette[ !!($byte & 0x08) ]); imagesetpixel($img, $x+5, $y, $imagePalette[ !!($byte & 0x04) ]); imagesetpixel($img, $x+6, $y, $imagePalette[ !!($byte & 0x02) ]); imagesetpixel($img, $x+7, $y, $imagePalette[ !!($byte & 0x01) ]); } } break; } return $img; } ?> \modules\guild\emblem.php <?php if (!defined('FLUX_ROOT')) exit; function flux_get_default_bmp_data() { $filename = sprintf('%s/emblem/%s', FLUX_DATA_DIR, Flux::config('MissingEmblemBMP')); if (file_exists($filename)) { return file_get_contents($filename); } } function flux_display_empty_emblem() { $data = flux_get_default_bmp_data(); header("Content-Type: image/bmp"); header('Content-Length: '.strlen($data)); echo $data; exit; } if (Flux::config('ForceEmptyEmblem')) flux_display_empty_emblem(); $serverName = $params->get('login'); $athenaServerName = $params->get('charmap'); $guildID = intval($params->get('id')); $athenaServer = Flux::getAthenaServerByName($serverName, $athenaServerName); if (!$athenaServer || $guildID < 0) flux_display_empty_emblem(); else { if ($interval=Flux::config('EmblemCacheInterval')) { $interval *= 60; $dirname = FLUX_DATA_DIR."/tmp/emblems/$serverName/$athenaServerName"; $filename = "$dirname/$guildID.png"; if (!is_dir($dirname)) if (Flux::config('RequireOwnership')) mkdir($dirname, 0700, true); else mkdir($dirname, 0777, true); elseif (file_exists($filename) && (time() - filemtime($filename)) < $interval) { header("Content-Type: image/png"); header('Content-Length: '.filesize($filename)); @readfile($filename); exit; } } $db = $athenaServer->charMapDatabase; $sql = "SELECT emblem_len, emblem_data FROM $db.guild WHERE guild_id = ? LIMIT 1"; $sth = $athenaServer->connection->getStatement($sql); $sth->execute(array($guildID)); $res = $sth->fetch(); if (!$res || !$res->emblem_len || is_null($res->emblem_data)) flux_display_empty_emblem(); else { $data = hex2bin($res->emblem_data); if ($data === false) { flux_display_empty_emblem(); exit; } $signature = substr($res->emblem_data, 0, 4); // First 2 bytes, because it's in hex $image_type = "image/png"; // Default if ($signature === "4749") { $image_type = "image/gif"; } elseif ($signature === "424D") { $image_type = "image/bmp"; require_once 'functions/imagecreatefrombmpstring.php'; $image = imagecreatefrombmpstring($data); if ($image === false) { flux_display_empty_emblem(); exit; } // Reassign $data to the PNG image data ob_start(); imagepng($image); $data = ob_get_contents(); ob_end_clean(); } elseif ($signature === "7801") { // Attempt zlib decompression $data = @gzuncompress($data); if ($data === false) { flux_display_empty_emblem(); exit; } // Here, further identification of the data type may be needed } header("Content-Type: {$image_type}"); header('Content-Length: '.strlen($data)); echo $data; exit; } } ?> -
View File Client Ally Chat Handler The plugin adds support for the Guild Ally Chat system introduced in RO clients from ~2023-06-07 onward. It handles alliance chat packets, allowing players to send messages to all members of their guild and allied guilds. I also provide optional client-side customization via HEX patching to change or disable the symbol (#) that triggers the ally chat. Compatible with the latest version of Hercules Successfully built on Windows (MSVC) and Debian 12 (GCC) Thoroughly tested with client version: 2025-03-19 Features Handles CZ/ZC_ALLY_CHAT packets from client and server Broadcasts messages to guild and allied members Optional HEX patch support for customizing or disabling the ally chat symbol Setup 1. Set PACKETVER >= 20230607 in /src/common/mmo.h 2. Recompile your Hercules server with the plugin Optional (HEX Patch) By default, the client uses # to send messages to the ally chat via public input. If you use # for server charcommands (e.g., #alive), this causes conflicts. To avoid this: - Apply the NewstyleChangeAllyChatSymbol patch to use a different symbol: !, %, ^, &, * - Or apply NewstyleDisableAllyChatSymbol to disable symbol-based access entirely HEX patches are available in the public repository: 🔗 https://github.com/AcidMarco/ro-releases Submitter AcidMarco Submitted 05/18/25 Category Plugins
-
Version 1.0.0
2 downloads
The plugin adds support for the Guild Ally Chat system introduced in RO clients from ~2023-06-07 onward. It handles alliance chat packets, allowing players to send messages to all members of their guild and allied guilds. I also provide optional client-side customization via HEX patching to change or disable the symbol (#) that triggers the ally chat. Compatible with the latest version of Hercules Successfully built on Windows (MSVC) and Debian 12 (GCC) Thoroughly tested with client version: 2025-03-19 Features Handles CZ/ZC_ALLY_CHAT packets from client and server Broadcasts messages to guild and allied members Optional HEX patch support for customizing or disabling the ally chat symbol Setup 1. Set PACKETVER >= 20230607 in /src/common/mmo.h 2. Recompile your Hercules server with the plugin Optional (HEX Patch) By default, the client uses # to send messages to the ally chat via public input. If you use # for server charcommands (e.g., #alive), this causes conflicts. To avoid this: - Apply the NewstyleChangeAllyChatSymbol patch to use a different symbol: !, %, ^, &, * - Or apply NewstyleDisableAllyChatSymbol to disable symbol-based access entirely HEX patches are available in the public repository: 🔗 https://github.com/AcidMarco/ro-releases -
View File Client New Emotion System and UI Handler The plugin adds full support for the new emotion system introduced in RO clients from ~2023-08-02 onward. It handles emotion playback packets, supports in-game emotion pack purchasing, and reads a configurable emotion pack database. Compatible with the latest version of Hercules Successfully built on Windows (MSVC) and Debian 12 (GCC) Thoroughly tested with client version: 2025-03-05 The plugin provides the following features 1. Handling of new emotion playback packets 2. Management and parsing of the emotion pack database 3. Functions for purchasing emotion packs in-game Setup 1. Set PACKETVER >= 20230802 in /src/common/mmo.h (make sure your client version supports the new emotion system) 2. Place emotion_pack_db.conf in your /db/ folder Optional Modify UI_CURRENCY_ID in the plugin. To change UI_CURRENCY_ID client-side, apply the HEX patch. Included in this post ns_client_emote_ui_handler.c — server plugin (HPM) emotion_pack_db.conf — emotion pack definitions Client-side files (LUB/UI/HEX patch) Client UI files, hex patch, and additional resources are available in the public repository: 🔗 https://github.com/AcidMarco/ro-releases Submitter AcidMarco Submitted 05/07/25 Category Plugins
-
Version 1.0.0
17 downloads
The plugin adds full support for the new emotion system introduced in RO clients from ~2023-08-02 onward. It handles emotion playback packets, supports in-game emotion pack purchasing, and reads a configurable emotion pack database. Compatible with the latest version of Hercules Successfully built on Windows (MSVC) and Debian 12 (GCC) Thoroughly tested with client version: 2025-03-05 The plugin provides the following features 1. Handling of new emotion playback packets 2. Management and parsing of the emotion pack database 3. Functions for purchasing emotion packs in-game Setup 1. Set PACKETVER >= 20230802 in /src/common/mmo.h (make sure your client version supports the new emotion system) 2. Place emotion_pack_db.conf in your /db/ folder Optional Modify UI_CURRENCY_ID in the plugin. To change UI_CURRENCY_ID client-side, apply the HEX patch. Included in this post ns_client_emote_ui_handler.c — server plugin (HPM) emotion_pack_db.conf — emotion pack definitions Client-side files (LUB/UI/HEX patch) Client UI files, hex patch, and additional resources are available in the public repository: 🔗 https://github.com/AcidMarco/ro-releases -
New Custom Item, Sprite not appearing when worn
AcidMarco replied to naouemi's question in General Server Support
If you want to change view ID of existed item, than you have to change it in itemdb (server side) and also in iteminfo (client side). And if you are going to use view IDs from 5000 and more, than input 10000 in the patch. And also double check these files, if your view id linked well: luafiles514\lua files\datainfo\accessoryid.lub luafiles514\lua files\datainfo\accname.lub