Skip to content

Commit

Permalink
Rev 1
Browse files Browse the repository at this point in the history
First version, still some problems with multithreading [crash], but it's
possible to generate map.
  • Loading branch information
gesior committed Jul 5, 2015
1 parent 0642fb6 commit 6eee8b9
Show file tree
Hide file tree
Showing 17 changed files with 460 additions and 67 deletions.
101 changes: 49 additions & 52 deletions README.md
@@ -1,68 +1,65 @@
[![Build Status](https://secure.travis-ci.org/edubart/otclient.svg?branch=master)](http://travis-ci.org/edubart/otclient) [![Join the chat at https://gitter.im/edubart/otclient](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/edubart/otclient?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
### What is otclient?
### What is this fork?

Otclient is an alternative Tibia client for usage with otserv. It aims to be complete and flexible,
for that it uses LUA scripting for all game interface functionality and configurations files with a syntax
similar to CSS for the client interface design. Otclient works with a modular system, this means
that each functionality is a separated module, giving the possibility to users modify and customize
anything easily. Users can also create new mods and extend game interface for their own purposes.
Otclient is written in C++2011, the upcoming C++ standard and heavily scripted in lua.
It's 100% automatic map image generator [for website view 'like GoogleMaps'].
It generates OTS map .png images (each 8x8 tiles).

### Where do I download?
### How to use?

The latest commits compiled for Windows can be found here.
* [Windows Builds](http://otland.net/threads/otclient-builds-windows.217977/)
1. Compile it like normal OTClient:
https://github.com/edubart/otclient/wiki/Compiling-on-Windows - CodeBlocks tutorial [harder, but less GB to download before compilation]
https://otland.net/threads/compiling-otclients-latest-source-with-microsoft-visual-studio-2013.204849/ - VisualStudio tutorial
https://github.com/edubart/otclient/wiki/Compiling-on-Linux
https://github.com/edubart/otclient/wiki/Compiling-on-Mac-OS-X
https://github.com/edubart/otclient/wiki/Compiling-for-Android

Here is the latest v0.6.5 release compiled for both i686(32 bit) and x86_64(64 bit) machines, with OpenGL renderer.
This release is compatible with protocols ranges from 7.60 up to 10.31.
* [For Windows](https://www.dropbox.com/sh/se1okacemoqzjve/XFqFoSKLCg/otclient-win-0.6.5.zip)
* [For Linux](https://www.dropbox.com/sh/se1okacemoqzjve/xKJL7j6vEo/otclient-linux-0.6.5.tar.gz)
2. Copy your server **client .spr and .dat** files to OTClient folder: **data/things/HERE_PROTOCOL_VERSION/**

**NOTE:** You will need to download spr/dat files on your own and place them in `data/things/VERSION/` (i.e: `data/things/1041/Tibia.spr`)
3. Copy your server **data/items/items.otb** file to OTClient folder: **data/things/HERE_PROTOCOL_VERSION/**

Older releases can be downloaded from [here](https://www.dropbox.com/sh/se1okacemoqzjve/-oWK4YFm03)
4. Copy your server /**ata/world/MAP_NAME.otbm** file to OTClient folder: **data/map.otbm**

### Features
5. Run otclient.exe

Beyond of it's flexibility with scripts, otclient comes with tons of other features that make possible
the creation of new client side stuff in otserv that was not possible before. These include,
sound system, graphics effects with shaders, modules/addons system, animated textures,
styleable user interface, transparency, multi language, in game lua terminal, an OpenGL 1.1/2.0 ES engine that make possible
to port to mobile platforms. Otclient is also flexible enough to
create tibia tools like map editors just using scripts, because it wasn't designed to be just a
client, instead otclient was designed to be a combination of a framework and tibia APIs.
6. Type in client terminal command like:

prepareClient(1076, '/things/1076/items.otb', '/map.otbm')

with you client protocol version and valid paths to items.otb and map.otbm
[Paths are relational, so start path with '/' to start in folder 'data', access to other folders is blocked]

### Compiling
7. OTClient will show in 10-50 seconds (it will freez client, do not close it, just wait) something like [pink text]:

A package with all required libraries for compiling OTClient on Windows can be found here:
* [For MSVC 2013](https://www.dropbox.com/sh/se1okacemoqzjve/dI4ODbq7OT/otclient-msvc13-libs.zip)
* [For MingW32](https://www.dropbox.com/sh/se1okacemoqzjve/UAkRCiGXXR/otclient-libs_mingw32-dwarf2.zip)
Example generator of whole map: generateMap(25, 45, 0, 555, 699, 15, 4) [last 4 = 4 threads to generate]

In short, if you need to compile OTClient, follow these tutorials:
* [Compiling on Windows](https://github.com/edubart/otclient/wiki/Compiling-on-Windows)
* [Compiling on Linux](https://github.com/edubart/otclient/wiki/Compiling-on-Linux)
* [Compiling on OS X](https://github.com/edubart/otclient/wiki/Compiling-on-Mac-OS-X)
8. Type in client terminal command:

**generateMap(25, 45, 0, 555, 699, 15, 4)**
OTClient will report progress in terminal.

Last **4** is number of threads to run in same time (only way to use more then 1 core to generate images).

If you are borded of getting 'crash' every few seconds/minutes [restart client and type all again..] you can set it to **1**.
It will take sooome time, but it will work for sure, so you can leave PC for night and get your map images.

### Need help?
**NOTE:** THERE ARE SOME PROBLEMS WITH MULTI THREADING! Read text below, if you want use more then 1 core of your CPU.

Try to ask questions in [otland](http://otland.net/f494/), now we have a board for the project there,
or talk with us at #otclient irc.freenode.net
There are some problems with multithreading [few threads try to access 1 tile in same time].
You can try to run X threads, wait for crash, check in file 'otclient.log' last 'area' generated ['X of XX...'] before crash.
Then when you start client again, in 'generateMap' command after number of threads, you can add 'start area' to skip already generated areas. Example:
**generateMap(25, 45, 0, 555, 699, 15, NUMBER_OF_THREADS, SKIP_AREAS)**
**Remember to set it to number of areas generated before MINUS number of threads.**

### Bugs

Have found a bug? Please create an issue in our [bug tracker](https://github.com/edubart/otclient/issues)

### Contributing

We encourage you to contribute to otclient! You can make pull requests of any improvement in our github page, alternatively, see [Contributing Wiki Page](https://github.com/edubart/otclient/wiki/Contributing).

### Contact

Talk directly with us at #otclient irc.freenode.net or send an email directly to the project leader edub4rt@gmail.com

### License

Otclient is made available under the MIT License, thus this means that you are free
to do whatever you want, commercial, non-commercial, closed or open.
So if client crashed with last message before 'debug ..':
**78 of 192 generated or are being generated right now, 4 threads are generating**
and last time your ran 7 threads, then after client restart type:
**prepareClient(1076, '/things/1076/items.otb', '/map.otbm') generateMap(25, 45, 0, 555, 699, 15, 7, 71)**
last parameter is **71** (78 - 7).

You can type few commands in one line with 'space' separator (like in code above: prepareClient and then generateMap)
10 changes: 1 addition & 9 deletions modules/client/client.lua
@@ -1,5 +1,4 @@
local musicFilename = "/sounds/startup"
local musicChannel = g_sounds.getChannel(1)

function setMusic(filename)
musicFilename = filename
Expand Down Expand Up @@ -27,12 +26,6 @@ end

function startup()
-- Play startup music (The Silver Tree, by Mattias Westlund)
musicChannel:enqueue(musicFilename, 3)
connect(g_game, { onGameStart = function() musicChannel:stop(3) end })
connect(g_game, { onGameEnd = function()
g_sounds.stopAll()
musicChannel:enqueue(musicFilename, 3)
end })

-- Check for startup errors
local errtitle = nil
Expand All @@ -48,7 +41,7 @@ function startup()
local msgbox = displayErrorBox(errtitle, errmsg)
msgbox.onOk = function() EnterGame.firstShow() end
else
EnterGame.firstShow()
modules.client_terminal.show()
end
end

Expand All @@ -57,7 +50,6 @@ function init()
onExit = exit })

g_window.setMinimumSize({ width = 600, height = 480 })
g_sounds.preload(musicFilename)

-- initialize in fullscreen mode on mobile devices
if g_window.getPlatformType() == "X11-EGL" then
Expand Down
2 changes: 1 addition & 1 deletion modules/client/client.otmod
Expand Up @@ -15,8 +15,8 @@ Module
- client_topmenu
- client_background
- client_options
- client_entergame
- client_terminal
- client_entergame
- client_modulemanager
- client_serverlist
- client_stats
6 changes: 3 additions & 3 deletions modules/client_options/options.lua
Expand Up @@ -185,16 +185,16 @@ function setOption(key, value, force)
elseif key == 'fullscreen' then
g_window.setFullscreen(value)
elseif key == 'enableAudio' then
g_sounds.setAudioEnabled(value)
--g_sounds.setAudioEnabled(value)
if value then
audioButton:setIcon('/images/topbuttons/audio')
else
audioButton:setIcon('/images/topbuttons/audio_mute')
end
elseif key == 'enableMusicSound' then
g_sounds.getChannel(SoundChannels.Music):setEnabled(value)
--g_sounds.getChannel(SoundChannels.Music):setEnabled(value)
elseif key == 'musicSoundVolume' then
g_sounds.getChannel(SoundChannels.Music):setGain(value/100)
--g_sounds.getChannel(SoundChannels.Music):setGain(value/100)
audioPanel:getChildById('musicSoundVolumeLabel'):setText(tr('Music volume: %d', value))
elseif key == 'showLeftPanel' then
modules.game_interface.getLeftPanel():setOn(value)
Expand Down
140 changes: 139 additions & 1 deletion otclientrc.lua
@@ -1,5 +1,143 @@
-- this file is loaded after all modules are loaded and initialized
-- you can place any custom user code here

print 'Startup done :]'
g_logger.info('Startup done :]')
g_logger.info("Step 1: prepare client to generate graphics, execute: prepareClient(1076, '/things/1076/items.otb', '/map.otbm')")


local clientVersion = 123
local otbPath = ''
local mapPath = ''

local areaSizeY = 25
local areaSizeX = 25
local isGenerating = false
local startTime = 0
local threadsToRun = 1
local areasList = {}
local areasIds = {}
local currentArea = 0
local lastPrintStatus = os.time()

-- ex. prepareClient(1076, '/things/1076/items.otb', '/map.otbm')
function prepareClient(cv, op, mp)
clientVersion = cv
otbPath = op
mapPath = mp
g_logger.info("Loading client data... (it will freez client for FEEEEW seconds)")
g_dispatcher.scheduleEvent(prepareClient_action, 1000)
end

function prepareClient_action()
g_map.initializeMapGenerator();
g_logger.info("Loading client Tibia.dat and Tibia.spr...")
g_game.setClientVersion(clientVersion)
g_logger.info("Loading server items.otb...")
g_things.loadOtb(otbPath)
g_logger.info("Loading server map...")
g_map.loadOtbm(mapPath)
g_logger.info("Loaded client data")
end

function threadsManager()
local threadsRunning = 0
local allFinished = true
for threadId = 0, threadsToRun - 1 do
if g_map.isThreadRunning(threadId) then
threadsRunning = threadsRunning + 1
allFinished = false
end
end
if currentArea == #areasList then
if allFinished then
isGenerating = false
print('Map image generation finished.')
print(currentArea .. ' areas generated [each up to ' .. (areaSizeX*areaSizeY) .. ' images] in ' .. (os.time() - startTime) .. ' seconds.')
return
end
end
if lastPrintStatus ~= os.time() then
print(currentArea .. ' of ' .. #areasList .. ' generated or are being generated right now, ' .. threadsRunning .. ' threads are generating')
lastPrintStatus = os.time()
end

-- there is no more areas to generate and we are just waiting for all threads to finish
if currentArea < #areasList then
for threadId = 0, threadsToRun - 1 do
if currentArea == #areasList then
break
end
if not g_map.isThreadRunning(threadId) then
currentArea = currentArea + 1
local areaId = areasIds[currentArea]
local area = areasList[areaId]
-- start new thread with given area
g_map.startThread(threadId, area[1], area[2], area[3], area[4], area[5], area[6])
end
end
end
g_dispatcher.scheduleEvent(threadsManager, 10)
end

function generateMap(minX, minY, minZ, maxX, maxY, maxZ, threadsCount, customCurrentArea)
if isGenerating then
print('Generating script is already running.')
return
end
isGenerating = true
areasList = {}
currentArea = 0
if customCurrentArea then
currentArea = customCurrentArea
end
-- threads number limit is set in engine in file 'mapio.cpp' in line: #define THREADS_NUMBER 128
if(threadsCount > 128) then
g_logger.debug('Notice: You tried to run ' .. threadsCount .. ' threads, but threads number limit is 128.')
threadsCount = 128
end
threadsToRun = threadsCount

-- block invalid values
minX = math.max(0, minX)
minY = math.max(0, minY)
minZ = math.max(0, minZ)

maxX = math.min(g_map.getSize().width, maxX)
maxY = math.min(g_map.getSize().height, maxY)
maxZ = math.min(16, maxZ) -- more then 16 floors? idk if it's possible

print('Generating areas list for tile positons: min{x=' .. minX .. ', y=' .. minY .. ', z=' .. minZ .. '} , max{x=' .. maxX .. ', y=' .. maxY .. ', z=' .. maxZ .. '}')
-- change to 8x8 tiles
minX = math.floor(minX / 8)
minY = math.floor(minY / 8)
maxX = math.floor(maxX / 8) + 1
maxY = math.floor(maxY / 8) + 1
for z = minZ, maxZ do
local startX = minX
local endX = minX + areaSizeX
while(startX < maxX) do
local startY = minY
local endY = minY + areaSizeY
while(startY < maxY) do
-- 1 floor, areaSizeY x areaSizeY 'areas' (each 8x8 tiles), up to 400 images to generate [no tiles in area = no image]
table.insert(areasList, {startX, startY, z, endX, endY, z})
--print(startX, startY, z, endX, endY, z)
startY = endY + 1
endY = endY + areaSizeY
end
startX = endX + 1
endX = endX + areaSizeX
end
end
-- we need some pseudo random order of areas generated to reduce chance of client crash
for i = 1, 7 do
local x = i
while x <= #areasList do
table.insert(areasIds, x)
x = x + 7
end
end
print('Generated list of ' .. #areasList .. ' areas. ' .. threadsCount .. ' threads will generate it now. Please wait.')
startTime = os.time()
g_dispatcher.scheduleEvent(threadsManager, 1000)
end
11 changes: 11 additions & 0 deletions src/client/item.cpp
Expand Up @@ -90,6 +90,17 @@ void Item::draw(const Point& dest, float scaleFactor, bool animate, LightView *l
g_painter->resetColor();
}

void Item::drawToImage(Point dest, ImagePtr image)
{
if(m_clientId == 0)
return;

int xPattern = 0, yPattern = 0, zPattern = 0;
calculatePatterns(xPattern, yPattern, zPattern);

rawGetThingType()->drawToImage(dest, xPattern, yPattern, zPattern, image);
}

void Item::setId(uint32 id)
{
if(!g_things.isValidDatId(id, ThingCategoryItem))
Expand Down
1 change: 1 addition & 0 deletions src/client/item.h
Expand Up @@ -83,6 +83,7 @@ class Item : public Thing
static ItemPtr createFromOtb(int id);

void draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView = nullptr);
void drawToImage(Point dest, ImagePtr image);

void setId(uint32 id);
void setOtbId(uint16 id);
Expand Down
5 changes: 5 additions & 0 deletions src/client/luafunctions.cpp
Expand Up @@ -103,6 +103,11 @@ void Client::registerLuaFunctions()
g_lua.bindSingletonFunction("g_sprites", "getSpritesCount", &SpriteManager::getSpritesCount, &g_sprites);

g_lua.registerSingletonClass("g_map");
g_lua.bindSingletonFunction("g_map", "initializeMapGenerator", &Map::initializeMapGenerator, &g_map);
g_lua.bindSingletonFunction("g_map", "isThreadRunning", &Map::isThreadRunning, &g_map);
g_lua.bindSingletonFunction("g_map", "startThread", &Map::startThread, &g_map);
g_lua.bindSingletonFunction("g_map", "drawMap", &Map::drawMap, &g_map);

g_lua.bindSingletonFunction("g_map", "isLookPossible", &Map::isLookPossible, &g_map);
g_lua.bindSingletonFunction("g_map", "isCovered", &Map::isCovered, &g_map);
g_lua.bindSingletonFunction("g_map", "isCompletelyCovered", &Map::isCompletelyCovered, &g_map);
Expand Down
5 changes: 5 additions & 0 deletions src/client/map.h
Expand Up @@ -149,6 +149,11 @@ class Map
bool loadOtcm(const std::string& fileName);
void saveOtcm(const std::string& fileName);

void initializeMapGenerator();
bool isThreadRunning(int threadId);
void startThread(int threadId, int minx, int miny, int minz, int maxx, int maxy, int maxz);
void drawMap(std::string fileName, int sx, int sy, int sz, int size);

void loadOtbm(const std::string& fileName);
void saveOtbm(const std::string& fileName);

Expand Down

0 comments on commit 6eee8b9

Please sign in to comment.