Merge branch 'master' of github.com:mc-server/MCServer
commit
94ca07cfbf
|
@ -7,10 +7,11 @@ Symbols
|
||||||
cloc-ignored.txt
|
cloc-ignored.txt
|
||||||
cloc.xml
|
cloc.xml
|
||||||
cloc.xsl
|
cloc.xsl
|
||||||
*.ncb
|
*.ncb
|
||||||
*.user
|
*.user
|
||||||
*.suo
|
*.suo
|
||||||
/EveryNight.cmd
|
/EveryNight.cmd
|
||||||
|
/UploadLuaAPI.cmd
|
||||||
|
|
||||||
# IDE Stuff
|
# IDE Stuff
|
||||||
## Sublime Text
|
## Sublime Text
|
||||||
|
@ -57,7 +58,44 @@ MCServer.dir/
|
||||||
|
|
||||||
#win32 cmake stuff
|
#win32 cmake stuff
|
||||||
*.vcxproj
|
*.vcxproj
|
||||||
|
*.vcproj
|
||||||
*.vcxproj.filters
|
*.vcxproj.filters
|
||||||
*.opensdf
|
*.opensdf
|
||||||
*.sdf
|
*.sdf
|
||||||
*.sln
|
*.sln
|
||||||
|
|
||||||
|
#cmake output folders
|
||||||
|
ZERO_CHECK.dir/
|
||||||
|
lib/cryptopp/Debug/
|
||||||
|
lib/cryptopp/Release/
|
||||||
|
lib/cryptopp/cryptopp.dir/
|
||||||
|
lib/expat/Debug/
|
||||||
|
lib/expat/Release/
|
||||||
|
lib/expat/expat.dir/
|
||||||
|
lib/inifile/Debug/
|
||||||
|
lib/inifile/Release/
|
||||||
|
lib/inifile/inifile.dir/
|
||||||
|
lib/jsoncpp/Debug/
|
||||||
|
lib/jsoncpp/Release/
|
||||||
|
lib/jsoncpp/jsoncpp.dir/
|
||||||
|
lib/lua/Debug/
|
||||||
|
lib/lua/Release/
|
||||||
|
lib/lua/lua.dir/
|
||||||
|
lib/luaexpat/Debug/
|
||||||
|
lib/luaexpat/Release/
|
||||||
|
lib/luaexpat/luaexpat.dir/
|
||||||
|
lib/md5/Debug/
|
||||||
|
lib/md5/Release/
|
||||||
|
lib/md5/md5.dir/
|
||||||
|
lib/sqlite/Debug/
|
||||||
|
lib/sqlite/Release/
|
||||||
|
lib/sqlite/sqlite.dir/
|
||||||
|
lib/tolua++/Debug/
|
||||||
|
lib/tolua++/Release/
|
||||||
|
lib/tolua++/tolua.dir/
|
||||||
|
lib/tolua++/tolualib.dir/
|
||||||
|
lib/zlib/Debug/
|
||||||
|
lib/zlib/Release/
|
||||||
|
lib/zlib/zlib.dir/
|
||||||
|
src/Debug/
|
||||||
|
src/Release/
|
||||||
|
|
|
@ -5,7 +5,7 @@ LOCAL_MODULE := mcserver
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LOCAL_SRC_FILES := $(shell find ../CryptoPP ../lua-5.1.4 ../jsoncpp-src-0.5.0 ../zlib-1.2.7 ../source ../squirrel_3_0_1_stable ../tolua++-1.0.93 ../iniFile ../WebServer ../expat '(' -name '*.cpp' -o -name '*.c' ')')
|
LOCAL_SRC_FILES := $(shell find ../CryptoPP ../lua ../jsoncpp ../zlib ../src ../tolua++ ../iniFile ../expat ../md5 ../sqlite ../luaexpat '(' -name '*.cpp' -o -name '*.c' ')')
|
||||||
LOCAL_SRC_FILES := $(filter-out %SquirrelFunctions.cpp %SquirrelBindings.cpp %cPlugin_Squirrel.cpp %cSquirrelCommandBinder.cpp %minigzip.c %lua.c %tolua.c %toluabind.c %LeakFinder.cpp %StackWalker.cpp %example.c,$(LOCAL_SRC_FILES))
|
LOCAL_SRC_FILES := $(filter-out %SquirrelFunctions.cpp %SquirrelBindings.cpp %cPlugin_Squirrel.cpp %cSquirrelCommandBinder.cpp %minigzip.c %lua.c %tolua.c %toluabind.c %LeakFinder.cpp %StackWalker.cpp %example.c,$(LOCAL_SRC_FILES))
|
||||||
LOCAL_SRC_FILES := $(patsubst %.cpp,../%.cpp,$(LOCAL_SRC_FILES))
|
LOCAL_SRC_FILES := $(patsubst %.cpp,../%.cpp,$(LOCAL_SRC_FILES))
|
||||||
LOCAL_SRC_FILES := $(patsubst %.c,../%.c,$(LOCAL_SRC_FILES))
|
LOCAL_SRC_FILES := $(patsubst %.c,../%.c,$(LOCAL_SRC_FILES))
|
||||||
|
@ -20,23 +20,21 @@ LOCAL_CFLAGS := -DANDROID_NDK \
|
||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES := cpufeatures
|
LOCAL_STATIC_LIBRARIES := cpufeatures
|
||||||
|
|
||||||
LOCAL_C_INCLUDES := ../source \
|
LOCAL_C_INCLUDES := ../src \
|
||||||
../source/md5 \
|
../src/packets \
|
||||||
../WebServer \
|
../src/items \
|
||||||
../source/packets \
|
../src/blocks \
|
||||||
../source/items \
|
../tolua++/src/lib \
|
||||||
../source/blocks \
|
../lua/src \
|
||||||
../tolua++-1.0.93/src/lib \
|
|
||||||
../lua-5.1.4/src \
|
|
||||||
../zlib-1.2.7 \
|
../zlib-1.2.7 \
|
||||||
../iniFile \
|
../iniFile \
|
||||||
../tolua++-1.0.93/include \
|
../tolua++/include \
|
||||||
../jsoncpp-src-0.5.0/include \
|
../jsoncpp/include \
|
||||||
../jsoncpp-src-0.5.0/src/lib_json \
|
../jsoncpp/src/lib_json \
|
||||||
../squirrel_3_0_1_stable/include \
|
|
||||||
../squirrel_3_0_1_stable \
|
|
||||||
../squirrel_3_0_1_stable/sqrat \
|
|
||||||
../expat/ \
|
../expat/ \
|
||||||
|
../md5/ \
|
||||||
|
../sqlite/ \
|
||||||
|
../luaexpat/ \
|
||||||
.. \
|
.. \
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "OSSupport/CriticalSection.h"
|
#include "OSSupport/CriticalSection.h"
|
||||||
#include "OSSupport/MakeDir.h"
|
#include "OSSupport/File.h"
|
||||||
#include "ToJava.h"
|
#include "ToJava.h"
|
||||||
|
|
||||||
#include "Root.h"
|
#include "Root.h"
|
||||||
|
@ -84,7 +84,7 @@ extern "C" void Java_com_mcserver_MCServerActivity_NativeOnCreate( JNIEnv* env,
|
||||||
//__android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "Logging from C++!");
|
//__android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "Logging from C++!");
|
||||||
g_CriticalSection.Unlock();
|
g_CriticalSection.Unlock();
|
||||||
|
|
||||||
mkdir("/sdcard/mcserver", S_IRWXU | S_IRWXG | S_IRWXO);
|
cFile::CreateFolder("/sdcard/mcserver");
|
||||||
|
|
||||||
pRoot = new cRoot();
|
pRoot = new cRoot();
|
||||||
pRoot->Start();
|
pRoot->Start();
|
||||||
|
@ -105,7 +105,7 @@ extern "C" void Java_com_mcserver_MCServerActivity_NativeCleanUp( JNIEnv* env,
|
||||||
__android_log_print(ANDROID_LOG_ERROR,"MCServer", "pRoot: %p", pRoot);
|
__android_log_print(ANDROID_LOG_ERROR,"MCServer", "pRoot: %p", pRoot);
|
||||||
if( pRoot != NULL )
|
if( pRoot != NULL )
|
||||||
{
|
{
|
||||||
pRoot->ExecuteConsoleCommand("stop");
|
pRoot->QueueExecuteConsoleCommand("stop");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ extern "C" jint Java_com_mcserver_MCServerActivity_NativeGetWebAdminPort( JNIEnv
|
||||||
{
|
{
|
||||||
if( pRoot != NULL && pRoot->GetWebAdmin() != NULL )
|
if( pRoot != NULL && pRoot->GetWebAdmin() != NULL )
|
||||||
{
|
{
|
||||||
return pRoot->GetWebAdmin()->GetPort();
|
return atoi(pRoot->GetWebAdmin()->GetIPv4Ports().c_str());
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" >
|
||||||
|
|
||||||
|
|
||||||
|
</TextView>
|
|
@ -83,7 +83,13 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
add_definitions(-DCRYPTOPP_DISABLE_ASM)
|
add_definitions(-DCRYPTOPP_DISABLE_ASM)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-DLUA_USE_DLOPEN)
|
# Under Windows, we need Lua as DLL; on *nix we need it linked statically:
|
||||||
|
if (WIN32)
|
||||||
|
add_definitions(-DLUA_BUILD_AS_DLL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# The Expat library is linked in statically, make the source files aware of that:
|
||||||
|
add_definitions(-DXML_STATIC)
|
||||||
|
|
||||||
add_subdirectory(lib/inifile/)
|
add_subdirectory(lib/inifile/)
|
||||||
add_subdirectory(lib/jsoncpp/)
|
add_subdirectory(lib/jsoncpp/)
|
||||||
|
@ -106,10 +112,13 @@ else()
|
||||||
add_flags("/Wall")
|
add_flags("/Wall")
|
||||||
endif()
|
endif()
|
||||||
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE_BAK}")
|
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE_BAK}")
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -rdynamic")
|
if (NOT WIN32)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -rdynamic")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")
|
||||||
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_PROFILE} -rdynamic")
|
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -rdynamic")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -rdynamic")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_PROFILE} -rdynamic")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory (src)
|
add_subdirectory (src)
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
COMPILING
|
|
||||||
=========
|
|
||||||
|
|
||||||
To compile MCServer on *nix, you need a GNUmake-compatible make that reads GNUmakefile.
|
|
||||||
Run "make" to build a debug version (slow, but gives more info on crash)
|
|
||||||
Run "make release=1" to build a release version (fast, less info on crash)
|
|
||||||
Add addm32=1 to compile in 32-bit mode on 64-bit systems.
|
|
||||||
Add `-j 4` to use 4 threads and speed up compilation on multi-core devices.
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
COMPILING
|
||||||
|
=========
|
||||||
|
|
||||||
|
To compile MCServer on *nix, you need CMake and make, as well as a C compiler, C++ compiler and linker.
|
||||||
|
|
||||||
|
Release Mode
|
||||||
|
------------
|
||||||
|
|
||||||
|
Release mode is preferred for almost all cases, it has much better speed and less console spam. However, if you are developing MCServer actively, debug mode might be better.
|
||||||
|
|
||||||
|
cmake . -DCMAKE_BUILD_TYPE=RELEASE && make
|
||||||
|
|
||||||
|
Debug Mode
|
||||||
|
----------
|
||||||
|
|
||||||
|
Debug mode is useful if you want more debugging information about MCServer as it's running or if you want to use a debugger like GDB to debug issues and crashes.
|
||||||
|
|
||||||
|
cmake . -DCMAKE_BUILD_TYPE=DEBUG && make
|
||||||
|
|
||||||
|
32 Bit Mode
|
||||||
|
-----------
|
||||||
|
|
||||||
|
This is useful if you want to compile MCServer to use on another 32-bit machine. It can be used with debug or release mode. To use 32 bit mode, simply add:
|
||||||
|
|
||||||
|
-DFORCE_32=1
|
||||||
|
|
||||||
|
to your cmake command and 32 bit will be forced.
|
|
@ -17,5 +17,7 @@ Sofapriester
|
||||||
mborland
|
mborland
|
||||||
SamJBarney
|
SamJBarney
|
||||||
worktycho
|
worktycho
|
||||||
|
Sxw1212
|
||||||
|
tonibm19
|
||||||
|
|
||||||
Please add yourself to this list if you contribute to MCServer.
|
Please add yourself to this list if you contribute to MCServer.
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
Hello! Thanks for wanting to work on this project :smile:, and I hope that this file will help you somewhat in getting all set up and running. I'll go through the basics of getting the projet environment set up, the code organization and style, and general development practices. I'll also show you some good issues to start off working on to get yourself familiarised with the code.
|
||||||
|
|
||||||
|
Minecraft Basics
|
||||||
|
----------------
|
||||||
|
|
||||||
|
If you don't play Minecraft or don't have a great knowledge of the basic systems, you should get to know them. The [Minecraft Wiki](http://minecraft.gamepedia.com/Minecraft_Wiki) is quite useful for this task, although some youtubers are also fairly good at teaching the basics and just playing is quite good too.
|
||||||
|
|
||||||
|
I'd say that the important topics are:
|
||||||
|
|
||||||
|
* Differnt types of blocks and how they act.
|
||||||
|
* Mobs, what they do and how.
|
||||||
|
* Redstone, pistons, and automation.
|
||||||
|
* Farming
|
||||||
|
* Fighting, health and the hunger system.
|
||||||
|
|
||||||
|
Useful Resources
|
||||||
|
----------------
|
||||||
|
|
||||||
|
* [Minecraft Wiki](http://minecraft.gamepedia.com/Minecraft_Wiki)
|
||||||
|
* [Minecraft Protocol Wiki](http://wiki.vg)
|
||||||
|
* [Lua API Documentation](http://mc-server.xoft.cz/LuaAPI)
|
||||||
|
* [VS2008 Download](http://stackoverflow.com/questions/15318560/visual-c-2008-express-download-link-dead)
|
||||||
|
|
||||||
|
Setting up a Dev Environment
|
||||||
|
============================
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
**Linux/BSD/Solaris/OSX:**
|
||||||
|
|
||||||
|
You'll need the basic C++ build tools:
|
||||||
|
|
||||||
|
* gcc (or clang or another C compiler)
|
||||||
|
* g++ (or clang++ or another C++ compiler)
|
||||||
|
* make
|
||||||
|
|
||||||
|
You'll also need CMake to generate the makefile to build from.
|
||||||
|
|
||||||
|
**Windows:**
|
||||||
|
|
||||||
|
If you use Windows, your best bet is the MSVC2008 (available as a free download in the Express edition from MS) or MSVS2013 (ditto), solution files for both are currently in the repo.
|
||||||
|
|
||||||
|
Setting up the Repo
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Next, you'll need to set up the repo. You can make a fork and work on that then PR in, or I can set you up with membership for the repo so you can work on branches here (still use PRs though, they're great tools and for the first few you'll definitely need some changes). If you want membership to the repo, just create an issue and I can set you up.
|
||||||
|
|
||||||
|
Once you've cloned, you need to pull down the submodules:
|
||||||
|
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
After that they should come down automatically when you pull but it's not bad to refresh every once in a while.
|
||||||
|
|
||||||
|
Repo Arrangement
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
The MCServer repo has recently been rearranged for better code separation and other things, but basically it's split into a few areas:
|
||||||
|
|
||||||
|
* `src`
|
||||||
|
This holds all of the MCServer source code, and is where most development takes place.
|
||||||
|
It's split into logical areas for blocks, the protocol handling and other things.
|
||||||
|
* `lib`
|
||||||
|
This holds all the 3rd party libraries for MCServer. You basically don't need to touch these, and we're thinking of switching them into submodules soon.
|
||||||
|
* `MCServer`
|
||||||
|
This folder isn't greatly named, but it contains the default plugins and environment to actually run the server. You'll find the executable (named `MCServer`) here and in the `plugins` subdir the default plugins. The config files are also stored here. Config files with `.example.ini` on the end are generated by the server or source control and should be left alone, instead you should copy them to a file without the `example` in the name which will be prioritised over the generated ones.
|
||||||
|
|
||||||
|
Code Styles
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Mainly follow the code styles in [CONTRIBUTING.md](https://github.com/mc-server/MCServer/blob/master/CONTRIBUTING.md), which is definitely an important read.
|
||||||
|
|
||||||
|
|
||||||
|
How to Build
|
||||||
|
------------------
|
||||||
|
|
||||||
|
**Linux/BSD/Solaris/OSX:**
|
||||||
|
|
||||||
|
Follow the instructions in [COMPILING.md](https://github.com/mc-server/MCServer/blob/master/COMPILING.md). You probably want to build in debug mode (when you're developing) for console alerts and debugging capability, even though it's much slower for everyday use.
|
||||||
|
|
||||||
|
Basically, the process is:
|
||||||
|
|
||||||
|
cmake . -DCMAKE_BUILD_TYPE=DEBUG && make
|
||||||
|
|
||||||
|
**Windows:**
|
||||||
|
|
||||||
|
You need to first execute the `src/Bindings/AllToLua.bat` script file, then just open the solution file in your MSVC of choice and build.
|
||||||
|
|
||||||
|
How to Run
|
||||||
|
----------
|
||||||
|
|
||||||
|
The server can be run (on *nix) by a simple `./MCServer` in the `MCServer` directory. On first run it will generate the world and start a server on the default port (configurable in `settings.ini`) so you can connect in minecraft via `localhost`.
|
||||||
|
|
||||||
|
Where to Get Started
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
There are a few fairly easy issues for you to get started with, as well as some more difficult but interesting ones.
|
||||||
|
|
||||||
|
**Easy**:
|
||||||
|
|
||||||
|
* #288
|
||||||
|
* #385
|
||||||
|
* #402
|
||||||
|
* #388
|
||||||
|
* #380
|
||||||
|
* Clean up some of the compiler warnings. (Check [Travis CI](http://travis-ci.org/mc-server/MCServer) for a list of them.) With clang, there are over 10000 lines of warnings to clean up.
|
||||||
|
|
||||||
|
**More Difficult**:
|
||||||
|
|
||||||
|
* #17
|
||||||
|
* #418
|
||||||
|
* #398
|
||||||
|
|
||||||
|
You may also want to write some plugins. They are written in lua, with excellent API documentation available via [APIDump](http://mc-server.xoft.cz/LuaAPI). The [Core](https://github.com/mc-server/Core) plugin should also help quite a bit here.
|
||||||
|
|
||||||
|
Special Things
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
* MCServer uses ToLUA for the Lua API, and you'll really have to ask @madmaxoft for how to export stuff and @worktycho for how to add stuff to the auto generated bindings (he just re-worked it with CMake).
|
||||||
|
* Ask questions as much as you like, we're here to help :smiley:
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
-- APIDesc.lua
|
-- APIDesc.lua
|
||||||
|
|
||||||
-- Contains the API objects' descriptions
|
-- Contains the API objects' descriptions
|
||||||
|
@ -308,18 +307,15 @@ g_APIDesc =
|
||||||
A wrapper class for constants representing colors or effects.
|
A wrapper class for constants representing colors or effects.
|
||||||
]],
|
]],
|
||||||
|
|
||||||
Functions =
|
Functions = {},
|
||||||
{
|
|
||||||
MakeColor = { Params = "ColorCodeConstant", Return = "string", Notes = "Creates the complete color-code-sequence from the color or effect constant" },
|
|
||||||
},
|
|
||||||
Constants =
|
Constants =
|
||||||
{
|
{
|
||||||
Black = { Notes = "" },
|
Black = { Notes = "" },
|
||||||
Blue = { Notes = "" },
|
Blue = { Notes = "" },
|
||||||
Bold = { Notes = "" },
|
Bold = { Notes = "" },
|
||||||
Color = { Notes = "The first character of the color-code-sequence, §" },
|
Color = { Notes = "The first character of the color-code-sequence, <EFBFBD>" },
|
||||||
DarkPurple = { Notes = "" },
|
DarkPurple = { Notes = "" },
|
||||||
Delimiter = { Notes = "The first character of the color-code-sequence, §" },
|
Delimiter = { Notes = "The first character of the color-code-sequence, <EFBFBD>" },
|
||||||
Gold = { Notes = "" },
|
Gold = { Notes = "" },
|
||||||
Gray = { Notes = "" },
|
Gray = { Notes = "" },
|
||||||
Green = { Notes = "" },
|
Green = { Notes = "" },
|
||||||
|
@ -2764,6 +2760,8 @@ end
|
||||||
ExtraPages =
|
ExtraPages =
|
||||||
{
|
{
|
||||||
-- No sorting is provided for these, they will be output in the same order as defined here
|
-- No sorting is provided for these, they will be output in the same order as defined here
|
||||||
|
{ FileName = "Writing-a-MCServer-plugin.html", Title = "Writing a MCServer plugin" },
|
||||||
|
{ FileName = "SettingUpDecoda.html", Title = "Setting up the Decoda Lua IDE" },
|
||||||
{ FileName = "WebWorldThreads.html", Title = "Webserver vs World threads" },
|
{ FileName = "WebWorldThreads.html", Title = "Webserver vs World threads" },
|
||||||
}
|
}
|
||||||
} ;
|
} ;
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
return
|
||||||
|
{
|
||||||
|
HOOK_PLUGINS_LOADED =
|
||||||
|
{
|
||||||
|
CalledWhen = "All the enabled plugins have been loaded",
|
||||||
|
DefaultFnName = "OnPluginsLoaded", -- also used as pagename
|
||||||
|
Desc = [[
|
||||||
|
This callback gets called when the server finishes loading and initializing plugins. This is the
|
||||||
|
perfect occasion for a plugin to query other plugins through {{cPluginManager}}:GetPlugin() and
|
||||||
|
possibly start communicating with them using the {{cPlugin}}:Call() function.
|
||||||
|
]],
|
||||||
|
Params = {},
|
||||||
|
Returns = [[
|
||||||
|
The return value is ignored, all registered callbacks are called.
|
||||||
|
]],
|
||||||
|
CodeExamples =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Title = "CoreMessaging",
|
||||||
|
Desc = [[
|
||||||
|
This example shows how to implement the CoreMessaging functionality - messages to players will be
|
||||||
|
sent through the Core plugin, formatted by that plugin. As a fallback for when the Core plugin is
|
||||||
|
not present, the messages are sent directly by this code, unformatted.
|
||||||
|
]],
|
||||||
|
Code = [[
|
||||||
|
-- These are the fallback functions used when the Core is not present:
|
||||||
|
local function SendMessageFallback(a_Player, a_Message)
|
||||||
|
a_Player:SendMessage(a_Message);
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SendMessageSuccessFallback(a_Player, a_Message)
|
||||||
|
a_Player:SendMessage(a_Message);
|
||||||
|
end
|
||||||
|
|
||||||
|
local function SendMessageFailureFallback(a_Player, a_Message)
|
||||||
|
a_Player:SendMessage(a_Message);
|
||||||
|
end
|
||||||
|
|
||||||
|
-- These three "variables" will hold the actual functions to call.
|
||||||
|
-- By default they are initialized to the Fallback variants, but will be redirected to Core when all plugins load
|
||||||
|
SendMessage = SendMessageFallback;
|
||||||
|
SendMessageSuccess = SendMessageSuccessFallback;
|
||||||
|
SendMessageFailure = SendMessageFailureFallback;
|
||||||
|
|
||||||
|
-- The callback tries to connect to the Core, if successful, overwrites the three functions with Core ones
|
||||||
|
local function OnPluginsLoaded()
|
||||||
|
local CorePlugin = cPluginManager:Get():GetPlugin("Core");
|
||||||
|
if (CorePlugin == nil) then
|
||||||
|
-- The Core is not loaded, keep the Fallback functions
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Overwrite the three functions with Core functionality:
|
||||||
|
SendMessage = function(a_Player, a_Message)
|
||||||
|
CorePlugin:Call("SendMessage", a_Player, a_Message);
|
||||||
|
end
|
||||||
|
SendMessageSuccess = function(a_Player, a_Message)
|
||||||
|
CorePlugin:Call("SendMessageSuccess", a_Player, a_Message);
|
||||||
|
end
|
||||||
|
SendMessageFailure = function(a_Player, a_Message)
|
||||||
|
CorePlugin:Call("SendMessageFailure", a_Player, a_Message);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Global scope, register the callback:
|
||||||
|
cPluginManager.AddHook(cPluginManager.HOOK_PLUGINS_LOADED, CoreMessagingPluginsLoaded);
|
||||||
|
|
||||||
|
|
||||||
|
-- Usage, anywhere else in the plugin:
|
||||||
|
SendMessageFailure(a_Player, "Cannot teleport to player, the destination player " .. PlayerName .. " was not found");
|
||||||
|
]],
|
||||||
|
},
|
||||||
|
} , -- CodeExamples
|
||||||
|
}, -- HOOK_PLUGINS_LOADED
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>MCServer - Setting up Decoda</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="main.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="prettify.css" />
|
||||||
|
<script src="prettify.js"></script>
|
||||||
|
<script src="lang-lua.js"></script>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="content">
|
||||||
|
<h1>Setting up the Decoda IDE</h1>
|
||||||
|
<p>
|
||||||
|
This article will explain how to set up Decoda, an IDE for writing Lua code, so that you can develop MCServer plugins with the comfort of an IDE.</p>
|
||||||
|
|
||||||
|
<h2><img src="Static/decoda_logo.png" /> About Decoda</h2>
|
||||||
|
|
||||||
|
<p>To quickly introduce Decoda, it is an IDE for writing Lua code. It has the basic features expected of an IDE - you can group files into project, you can edit multiple files in a tabbed editor, the code is syntax-highlighted. Code completion, symbol browsing, and more. It also features a Lua debugger that allows you to debug your Lua code within any application that embeds the Lua runtime or uses Lua as a dynamic-link library (DLL). Although it is written using the multiplatform WxWidgets toolkit, it hasn't yet been ported to any platform other than 32-bit Windows. This unfortunately means that Linux users will not be able to use it. It can be used on 64-bit Windows, but the debugger only works for 32-bit programs.</p>
|
||||||
|
<p>Here's a screenshot of a default Decoda window with the debugger stepping through the code (scaled down):<br />
|
||||||
|
<img src="Static/decoda_workspace.png" /></p>
|
||||||
|
<p>As you can see, you can set breakpoints in the code, inspect variables' values, view both the Lua and native (C++) call-stacks. Decoda also breaks program execution when a faulty Lua script is executed, providing a detailed error message and pointing you directly to the faulting code. It is even possible to attach a C++ debugger to a process that is being debugged by Decoda, this way you can trap both C++ and Lua errors.</p>
|
||||||
|
<p>Decoda is open-source, the sources are on GitHub: <a href="https://github.com/unknownworlds/decoda">https://github.com/unknownworlds/decoda</a>. You can download a compiled binary from the creators' site, <a href="http://unknownworlds.com/decoda/">http://unknownworlds.com/decoda/</a>.
|
||||||
|
|
||||||
|
<h2><img src="Static/decoda_logo.png" /> Project management</h2>
|
||||||
|
<p>To begin using Decoda, you need to create a project, or load an existing one. Decoda projects have a .deproj extension, and are simply a list of Lua files that are to be opened. You can create a project through menu Project -> New Project. Save your project first, so that Decoda knows what relative paths to use for the files. Then either add existing Lua files or create new one, through menu Project -> Add Add New File / Add Existing File.</p>
|
||||||
|
<p>Next you need to set up the executable that Decoda will run when debugging your files. Select menu Project -> Settings. A new dialog will open:<br />
|
||||||
|
<img src="Static/decoda_debug_settings.png" /></p>
|
||||||
|
<p>In the debugging section, fill in the full path to MCServer.exe, or click the triple-dot button to browse for the file. Note that the Working directory will be automatically filled in for you with the folder where the executable is (until the last backslash). This is how it's supposed to work, don't change it; if it for some reason doesn't update, copy and paste the folder name from the Command edit box. All done, you can close this dialog now.</p>
|
||||||
|
|
||||||
|
<h2><img src="Static/decoda_logo.png" /> Debugging</h2>
|
||||||
|
<p>You are now ready to debug your code. Before doing that, though, don't forget to save your project file. If you haven't done so already, enable your plugin in the settings.ini file. If you want the program to break at a certain line, it is best to set the breakpoint before starting the program. Set the cursor on the line and hit F9 (or use menu Debug -> Toggle Breakpoint) to toggle a breakpoint on that line. Finally, hit F5, or select menu Debug -> Start to launch MCServer under the debugger. The MCServer window comes up and loads your plugin. If Decoda displays the Project Settings dialog instead, you haven't set up the executable to run, see the Project management section for instructions.</p>
|
||||||
|
<p>At this point you will see that Decoda starts adding new items to your project. All the files for all plugins are added temporarily. Don't worry, they are only temporary, they will be removed again once the debugging session finishes. You can tell the temporary files from the regular files by their icon, it's faded out. Decoda handles all the files that MCServer loads, so you can actually debug any of those faded files, too.</p>
|
||||||
|
<p>If there's an error in the code, the Decoda window will flash and a dialog box will come up, describing the error and taking you to the line where it occured. Note that the execution is paused in the thread executing the plugin, so until you select Debug -> Continue from the menu (F5), MCServer won't be fully running. You can fix the error and issue a "reload" command in MCServer console to reload the plugin code anew (MCServer doesn't detect changes in plugin code automatically).</p>
|
||||||
|
<p>If the execution hits a breakpoint, the Decoda window will flash and a yellow arrow is displayed next to the line. You can step through the code using F10 and F11, just like in MSVS. You can also use the Watch window to inspect variable values, or simply hover your mouse over a variable to display its value in the tooltip.</p>
|
||||||
|
|
||||||
|
<h2><img src="Static/decoda_logo.png" /> Limitations</h2>
|
||||||
|
<p>So far everything seems wonderful. Unfortunately, it doesn't always go as easy. There are several limits to what Decoda can do:</p>
|
||||||
|
<ul>
|
||||||
|
<li>When the program encounters a logical bug (using a nil value, calling a non-existent function etc.), Decoda will break, but usually the Watch window and the tooltips are showing nonsense values. You shouldn't trust them in such a case, if you kep running into such a problem regularly, put console logging functions (LOG) in the code to print out any info you need prior to the failure.</li>
|
||||||
|
<li>Sometimes breakpoints just don't work. This is especially true if there are multiple plugins that have files of the same name. Breakpoints will never work after changing the code and reloading the plugin in MCServer; you need to stop the server and start again to reenable breakpoints.</li>
|
||||||
|
<li>Most weirdly, sometimes Decoda reports an error, but instead of opening the current version of the file, opens up another window with old contents of the file. Watch for this, because you could overwrite your new code if you saved this file over your newer file. Fortunately enough, Decoda will always ask you for a filename before saving such a file.</li>
|
||||||
|
<li>Decoda stores the project in two files. The .deproj file has the file list, and should be put into version control systems. The .deuser file has the settings (debugged application etc.) and is per-user specific. This file shouldn't go to version control systems, because each user may have different paths for the debuggee.</li>
|
||||||
|
<li>Unfortunately for us Windows users, the Decoda project file uses Unix-lineends (CR only). This makes it problematic when checking the file into a version control system, since those usually expect windows (CRLF) lineends; I personally convert the lineends each time I edit the project file using <a href="http://jsimlo.sk/notepad/">TED Notepad</a>.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
|
@ -6,64 +6,67 @@
|
||||||
<link rel="stylesheet" type="text/css" href="prettify.css" />
|
<link rel="stylesheet" type="text/css" href="prettify.css" />
|
||||||
<script src="prettify.js"></script>
|
<script src="prettify.js"></script>
|
||||||
<script src="lang-lua.js"></script>
|
<script src="lang-lua.js"></script>
|
||||||
|
<meta charset="UTF-8">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Webserver vs World threads</h1>
|
<div id="content">
|
||||||
<p>
|
<h1>Webserver vs World threads</h1>
|
||||||
This article will explain the threading issues that arise between the webserver and world threads are of concern to plugin authors.</p>
|
<p>
|
||||||
<p>
|
This article will explain the threading issues that arise between the webserver and world threads are of concern to plugin authors.</p>
|
||||||
Generally, plugins that provide webadmin pages should be quite careful about their interactions. Most operations on MCServer objects requires synchronization, that MCServer provides automatically and transparently to plugins - when a block is written, the chunkmap is locked, or when an entity is being manipulated, the entity list is locked. Each plugin also has a mutex lock, so that only one thread at a time may be executing plugin code.</p>
|
<p>
|
||||||
<p>
|
Generally, plugins that provide webadmin pages should be quite careful about their interactions. Most operations on MCServer objects requires synchronization, that MCServer provides automatically and transparently to plugins - when a block is written, the chunkmap is locked, or when an entity is being manipulated, the entity list is locked. Each plugin also has a mutex lock, so that only one thread at a time may be executing plugin code.</p>
|
||||||
This locking can be a source of deadlocks for plugins that are not written carefully.</p>
|
<p>
|
||||||
|
This locking can be a source of deadlocks for plugins that are not written carefully.</p>
|
||||||
|
|
||||||
<h2>Example scenario</h2>
|
<h2>Example scenario</h2>
|
||||||
<p>Consider the following example. A plugin provides a webadmin page that allows the admin to kick players off the server. When the admin presses the "Kick" button, the plugin calls cWorld:DoWithPlayer() with a callback to kick the player. Everything seems to be working fine now.</p>
|
<p>Consider the following example. A plugin provides a webadmin page that allows the admin to kick players off the server. When the admin presses the "Kick" button, the plugin calls cWorld:DoWithPlayer() with a callback to kick the player. Everything seems to be working fine now.</p>
|
||||||
<p>
|
<p>
|
||||||
A new feature is developed in the plugin, now the plugin adds a new in-game command so that the admins can kick players while they're playing the game. The plugin registers a command callback with cPluginManager.AddCommand(). Now there are problems bound to happen.</p>
|
A new feature is developed in the plugin, now the plugin adds a new in-game command so that the admins can kick players while they're playing the game. The plugin registers a command callback with cPluginManager.AddCommand(). Now there are problems bound to happen.</p>
|
||||||
<p>
|
<p>
|
||||||
Suppose that two admins are in, one is using the webadmin and the other is in-game. Both try to kick a player at the same time. The webadmin locks the plugin, so that it can execute the plugin code, but right at this moment the OS switches threads. The world thread locks the world so that it can access the list of in-game commands, receives the in-game command, it tries to lock the plugin. The plugin is already locked, so the world thread is put on hold. After a while, the webadmin thread is woken up again and continues processing. It tries to lock the world so that it can traverse the playerlist, but the lock is already held by the world thread. Now both threads are holding one lock each and trying to grab the other lock, and are therefore deadlocked.</p>
|
Suppose that two admins are in, one is using the webadmin and the other is in-game. Both try to kick a player at the same time. The webadmin locks the plugin, so that it can execute the plugin code, but right at this moment the OS switches threads. The world thread locks the world so that it can access the list of in-game commands, receives the in-game command, it tries to lock the plugin. The plugin is already locked, so the world thread is put on hold. After a while, the webadmin thread is woken up again and continues processing. It tries to lock the world so that it can traverse the playerlist, but the lock is already held by the world thread. Now both threads are holding one lock each and trying to grab the other lock, and are therefore deadlocked.</p>
|
||||||
|
|
||||||
<h2>How to avoid the deadlock</h2>
|
<h2>How to avoid the deadlock</h2>
|
||||||
<p>
|
<p>
|
||||||
There are two main ways to avoid such a deadlock. The first approach is using tasks: Everytime you need to execute a task inside a world, instead of executing it, queue it, using <a href="cWorld.html">cWorld</a>:QueueTask(). This handy utility can will call the given function inside the world's TickThread, thus eliminating the deadlock, because now there's only one thread. However, this approach will not let you get data back. You cannot query the player list, or the entities, or anything - because when the task runs, the webadmin page has already been served to the browser.</p>
|
There are two main ways to avoid such a deadlock. The first approach is using tasks: Everytime you need to execute a task inside a world, instead of executing it, queue it, using <a href="cWorld.html">cWorld</a>:QueueTask(). This handy utility can will call the given function inside the world's TickThread, thus eliminating the deadlock, because now there's only one thread. However, this approach will not let you get data back. You cannot query the player list, or the entities, or anything - because when the task runs, the webadmin page has already been served to the browser.</p>
|
||||||
<p>
|
<p>
|
||||||
To accommodate this, you'll need to use the second approach - preparing and caching data in the tick thread, possibly using callbacks. This means that the plugin will have global variables that will store the data, and update those variables when the data changes; then the webserver thread will only read those variables, instead of calling the world functions. For example, if a webpage was to display the list of currently connected players, the plugin should maintain a global variable, g_WorldPlayers, which would be a table of worlds, each item being a list of currently connected players. The webadmin handler would read this variable and create the page from it; the plugin would use HOOK_PLAYER_JOINED and HOOK_DISCONNECT to update the variable.</p>
|
To accommodate this, you'll need to use the second approach - preparing and caching data in the tick thread, possibly using callbacks. This means that the plugin will have global variables that will store the data, and update those variables when the data changes; then the webserver thread will only read those variables, instead of calling the world functions. For example, if a webpage was to display the list of currently connected players, the plugin should maintain a global variable, g_WorldPlayers, which would be a table of worlds, each item being a list of currently connected players. The webadmin handler would read this variable and create the page from it; the plugin would use HOOK_PLAYER_JOINED and HOOK_DISCONNECT to update the variable.</p>
|
||||||
|
|
||||||
<h2>What to avoid</h2>
|
<h2>What to avoid</h2>
|
||||||
<p>
|
<p>
|
||||||
Now that we know what the danger is and how to avoid it, how do we know if our code is susceptible?</p>
|
Now that we know what the danger is and how to avoid it, how do we know if our code is susceptible?</p>
|
||||||
<p>
|
<p>
|
||||||
The general rule of thumb is to avoid calling any functions that read or write lists of things in the webserver thread. This means most ForEach() and DoWith() functions. Only <a href="cRoot.html">cRoot</a>:ForEachWorld() is safe - because the list of worlds is not expected to change, so it is not guarded by a mutex. Getting and setting world's blocks is, naturally, unsafe, as is calling other plugins, or creating entities.</p>
|
The general rule of thumb is to avoid calling any functions that read or write lists of things in the webserver thread. This means most ForEach() and DoWith() functions. Only <a href="cRoot.html">cRoot</a>:ForEachWorld() is safe - because the list of worlds is not expected to change, so it is not guarded by a mutex. Getting and setting world's blocks is, naturally, unsafe, as is calling other plugins, or creating entities.</p>
|
||||||
|
|
||||||
<h2>Example</h2>
|
<h2>Example</h2>
|
||||||
The Core has the facility to kick players using the web interface. It used the following code for the kicking (inside the webadmin handler):
|
The Core has the facility to kick players using the web interface. It used the following code for the kicking (inside the webadmin handler):
|
||||||
<pre class="prettyprint lang-lua">
|
<pre class="prettyprint lang-lua">
|
||||||
local KickPlayerName = Request.Params["players-kick"]
|
local KickPlayerName = Request.Params["players-kick"]
|
||||||
local FoundPlayerCallback = function(Player)
|
local FoundPlayerCallback = function(Player)
|
||||||
if (Player:GetName() == KickPlayerName) then
|
if (Player:GetName() == KickPlayerName) then
|
||||||
Player:GetClientHandle():Kick("You were kicked from the game!")
|
Player:GetClientHandle():Kick("You were kicked from the game!")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
cRoot:Get():FindAndDoWithPlayer(KickPlayerName, FoundPlayerCallback)
|
cRoot:Get():FindAndDoWithPlayer(KickPlayerName, FoundPlayerCallback)
|
||||||
</pre>
|
</pre>
|
||||||
The cRoot:FindAndDoWithPlayer() is unsafe and could have caused a deadlock. The new solution is queue a task; but since we don't know in which world the player is, we need to queue the task to all worlds:
|
The cRoot:FindAndDoWithPlayer() is unsafe and could have caused a deadlock. The new solution is queue a task; but since we don't know in which world the player is, we need to queue the task to all worlds:
|
||||||
<pre class="prettyprint lang-lua">
|
<pre class="prettyprint lang-lua">
|
||||||
cRoot:Get():ForEachWorld( -- For each world...
|
cRoot:Get():ForEachWorld( -- For each world...
|
||||||
function(World)
|
function(World)
|
||||||
World:QueueTask( -- ... queue a task...
|
World:QueueTask( -- ... queue a task...
|
||||||
function(a_World)
|
function(a_World)
|
||||||
a_World:DoWithPlayer(KickPlayerName, -- ... to walk the playerlist...
|
a_World:DoWithPlayer(KickPlayerName, -- ... to walk the playerlist...
|
||||||
function (a_Player)
|
function (a_Player)
|
||||||
a_Player:GetClientHandle():Kick("You were kicked from the game!") -- ... and kick the player
|
a_Player:GetClientHandle():Kick("You were kicked from the game!") -- ... and kick the player
|
||||||
|
end
|
||||||
|
)
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
end
|
</pre>
|
||||||
)
|
<script>
|
||||||
</pre>
|
prettyPrint();
|
||||||
<script>
|
</script>
|
||||||
prettyPrint();
|
</div>
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -0,0 +1,263 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>MCS Plugin Tutorial</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="main.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="prettify.css" />
|
||||||
|
<script src="prettify.js"></script>
|
||||||
|
<script src="lang-lua.js"></script>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="content">
|
||||||
|
<h1>Writing a MCServer plugin</h1>
|
||||||
|
<p>
|
||||||
|
This article will explain how to write a basic plugin. It details basic requirements
|
||||||
|
for a plugin, explains how to register a hook and bind a command, and gives plugin
|
||||||
|
standards details.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Let us begin. In order to begin development, we must firstly obtain a compiled copy
|
||||||
|
of MCServer, and make sure that the Core plugin is within the Plugins folder, and activated.
|
||||||
|
Core handles much of the MCServer end-user experience and is a necessary component of
|
||||||
|
plugin development, as necessary plugin components depend on sone of its functions.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Next, we must obtain a copy of CoreMessaging.lua. This can be found
|
||||||
|
<a href="https://raw.github.com/mc-server/MCServer/master/MCServer/Plugins/MagicCarpet/coremessaging.lua">here.</a>
|
||||||
|
This is used to provide messaging support that is compliant with MCServer standards.
|
||||||
|
</p>
|
||||||
|
<h2>Creating the basic template</h2>
|
||||||
|
<p>
|
||||||
|
Plugins are written in Lua. Therefore, create a new Lua file. You can create as many files as you wish, with
|
||||||
|
any filename - MCServer bungs them all together at runtime, however, let us create a file called main.lua for now.
|
||||||
|
Format it like so:
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
local PLUGIN
|
||||||
|
|
||||||
|
function Initialize(Plugin)
|
||||||
|
Plugin:SetName("DerpyPlugin")
|
||||||
|
Plugin:SetVersion(1)
|
||||||
|
|
||||||
|
PLUGIN = Plugin
|
||||||
|
|
||||||
|
-- Hooks
|
||||||
|
|
||||||
|
local PluginManager = cPluginManager:Get()
|
||||||
|
-- Command bindings
|
||||||
|
|
||||||
|
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function OnDisable()
|
||||||
|
LOG(PLUGIN:GetName() .. " is shutting down...")
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Now for an explanation of the basics.
|
||||||
|
<ul>
|
||||||
|
<li><b>function Initialize</b> is called on plugin startup. It is the place where the plugin is set up.</li>
|
||||||
|
<li><b>Plugin:SetName</b> sets the name of the plugin.</li>
|
||||||
|
<li><b>Plugin:SetVersion</b> sets the revision number of the plugin. This must be an integer.</li>
|
||||||
|
<li><b>LOG</b> logs to console a message, in this case, it prints that the plugin was initialised.</li>
|
||||||
|
<li>The <b>PLUGIN</b> variable just stores this plugin's object, so GetName() can be called in OnDisable (as no Plugin parameter is passed there, contrary to Initialize).</li>
|
||||||
|
<li><b>function OnDisable</b> is called when the plugin is disabled, commonly when the server is shutting down. Perform cleanup and logging here.</li>
|
||||||
|
</ul>
|
||||||
|
Be sure to return true for this function, else MCS thinks you plugin had failed to initialise and prints a stacktrace with an error message.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Registering hooks</h2>
|
||||||
|
<p>
|
||||||
|
Hooks are things that MCServer calls when an internal event occurs. For example, a hook is fired when a player places a block, moves,
|
||||||
|
logs on, eats, and many other things. For a full list, see <a href="index.html">the API documentation</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
A hook can be either informative or overridable. In any case, returning false will not trigger a response, but returning true will cancel
|
||||||
|
the hook and prevent it from being propagated further to other plugins. An overridable hook simply means that there is visible behaviour
|
||||||
|
to a hook's cancellation, such as a chest being prevented from being opened. There are some exceptions to this where only changing the value the
|
||||||
|
hook passes has an effect, and not the actual return value, an example being the HOOK_KILLING hook. See the API docs for details.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
To register a hook, insert the following code template into the "-- Hooks" area in the previous code example.
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
cPluginManager.AddHook(cPluginManager.HOOK_NAME_HERE, FunctionNameToBeCalled)
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
What does this code do?
|
||||||
|
<ul>
|
||||||
|
<li><b>cPluginManager.AddHook</b> registers the hook. The hook name is the second parameter. See the previous API documentation link for a list of all hooks.</li>
|
||||||
|
</ul>
|
||||||
|
What about the third parameter, you ask? Well, it is the name of the function that MCServer calls when the hook fires. It is in this
|
||||||
|
function that you should handle or cancel the hook.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
So in total, this is a working representation of what we have so far covered.
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
function Initialize(Plugin)
|
||||||
|
Plugin:SetName("DerpyPlugin")
|
||||||
|
Plugin:SetVersion(1)
|
||||||
|
|
||||||
|
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
|
||||||
|
|
||||||
|
local PluginManager = cPluginManager:Get()
|
||||||
|
-- Command bindings
|
||||||
|
|
||||||
|
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function OnPlayerMoving(Player) -- See API docs for parameters of all hooks
|
||||||
|
return true -- Prohibit player movement, see docs for whether a hook is cancellable
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
So, that code stops the player from moving. Not particularly helpful, but yes :P. Note that ALL documentation is available
|
||||||
|
on the main API docs page, so if ever in doubt, go there.
|
||||||
|
</p>
|
||||||
|
<h2>Binding a command</h2>
|
||||||
|
<h3>Format</h3>
|
||||||
|
<p>
|
||||||
|
So now we know how to hook into MCServer, how do we bind a command, such as /explode, for a player to type? That is more complicated.
|
||||||
|
We firstly add this template to the "-- Command bindings" section of the initial example:
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
-- ADD THIS IF COMMAND DOES NOT REQUIRE A PARAMETER (/explode)
|
||||||
|
PluginManager:BindCommand("/commandname", "permissionnode", FunctionToCall, " - Description of command")
|
||||||
|
|
||||||
|
-- ADD THIS IF COMMAND DOES REQUIRE A PARAMETER (/explode Notch)
|
||||||
|
PluginManager:BindCommand("/commandname", "permissionnode", FunctionToCall, " ~ Description of command and parameter(s)")
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
What does it do, and why are there two?
|
||||||
|
<ul>
|
||||||
|
<li><b>PluginManager:BindCommand</b> binds a command. It takes the command name (with a slash), the permission a player needs to execute the command, the function
|
||||||
|
to call when the command is executed, and a description of the command.</li>
|
||||||
|
</ul>
|
||||||
|
The command name is pretty self explanatory. The permission node is basically just a <b>string</b> that the player's group needs to have, so you can have anything in there,
|
||||||
|
though we recommend a style such as "derpyplugin.explode". The function to call is like the ones with Hooks, but with some fixed parameters which we will come on to later,
|
||||||
|
and the description is a description of the command which is shown when "/help" is typed.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
So why are there two? Standards. A plugin that accepts a parameter MUST use a format for the description of " ~ Description of command and parms"
|
||||||
|
whereas a command that doesn't accept parameters MUST use " - Description of command" instead. Be sure to put a space before the tildes or dashes.
|
||||||
|
Additionally, try to keep the description brief and on one line on the client.
|
||||||
|
</p>
|
||||||
|
<h3>Parameters</h3>
|
||||||
|
<p>
|
||||||
|
What parameters are in the function MCServer calls when the command is executed? A 'Split' array and a 'Player' object.
|
||||||
|
</p>
|
||||||
|
<h4>The Split Array</h4>
|
||||||
|
<p>
|
||||||
|
The Split array is an array of all text submitted to the server, including the actual command. MCServer automatically splits the text into the array,
|
||||||
|
so plugin authors do not need to worry about that. An example of a Split array passed for the command, "/derp zubby explode" would be:<br /><br />
|
||||||
|
   /derp (Split[1])<br />
|
||||||
|
   zubby (Split[2])<br />
|
||||||
|
   explode (Split[3])<br />
|
||||||
|
<br />
|
||||||
|
   The total amount of parameters passed were: 3 (#Split)
|
||||||
|
</p>
|
||||||
|
<h4>The Player Object and sending them messages</h4>
|
||||||
|
<p>
|
||||||
|
The Player object is basically a pointer to the player that has executed the command. You can do things with them, but most common is sending
|
||||||
|
a message. Again, see the API documentation for fuller details. But, you ask, how <i>do</i> we send a message to the client?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Remember that copy of CoreMessaging.lua that we downloaded earlier? Make sure that file is in your plugin folder, along with the main.lua file you are typing
|
||||||
|
your code in. Since MCS brings all the files together on JIT compile, we don't need to worry about requiring any files or such. Simply follow the below examples:
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
-- Format: §yellow[INFO] §white%text% (yellow [INFO], white text following it)
|
||||||
|
-- Use: Informational message, such as instructions for usage of a command
|
||||||
|
SendMessage(Player, "Usage: /explode [player]")
|
||||||
|
|
||||||
|
-- Format: §green[INFO] §white%text% (green [INFO] etc.)
|
||||||
|
-- Use: Success message, like when a command executes successfully
|
||||||
|
SendMessageSuccess(Player, "Notch was blown up!")
|
||||||
|
|
||||||
|
-- Format: §rose[INFO] §white%text% (rose coloured [INFO] etc.)
|
||||||
|
-- Use: Failure message, like when a command was entered correctly but failed to run, such as when the destination player wasn't found in a /tp command
|
||||||
|
SendMessageFailure(Player, "Player Salted was not found")
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Those are the basics. If you want to output text to the player for a reason other than the three listed above, and you want to colour the text, simply concatenate
|
||||||
|
"cChatColor.*colorhere*" with your desired text, concatenate being "..". See the API docs for more details of all colours, as well as details on logging to console with
|
||||||
|
LOG("Text").
|
||||||
|
</p>
|
||||||
|
<h2>Final example and conclusion</h2>
|
||||||
|
<p>
|
||||||
|
So, a working example that checks the validity of a command, and blows up a player, and also refuses pickup collection to players with >100ms ping.
|
||||||
|
</p>
|
||||||
|
<pre class="prettyprint lang-lua">
|
||||||
|
function Initialize(Plugin)
|
||||||
|
Plugin:SetName("DerpyPluginThatBlowsPeopleUp")
|
||||||
|
Plugin:SetVersion(9001)
|
||||||
|
|
||||||
|
local PluginManager = cPluginManager:Get()
|
||||||
|
PluginManager:BindCommand("/explode", "derpyplugin.explode", Explode, " ~ Explode a player");
|
||||||
|
|
||||||
|
cPluginManager.AddHook(cPluginManager.HOOK_COLLECTING_PICKUP, OnCollectingPickup)
|
||||||
|
|
||||||
|
LOG("Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Explode(Split, Player)
|
||||||
|
if (#Split ~= 2) then
|
||||||
|
-- There was more or less than one argument (excluding the "/explode" bit)
|
||||||
|
-- Send the proper usage to the player and exit
|
||||||
|
SendMessage(Player, "Usage: /explode [playername]")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create a callback ExplodePlayer with parameter Explodee, which MCS calls for every player on the server
|
||||||
|
local HasExploded = false
|
||||||
|
local ExplodePlayer = function(Explodee)
|
||||||
|
-- If the player we are currently at is the one we specified as the parameter
|
||||||
|
if (Explodee:GetName() == Split[2]) then
|
||||||
|
-- Create an explosion at the same position as they are; see <a href="cWorld.html">API docs</a> for further details of this function
|
||||||
|
Player:GetWorld():DoExplosionAt(Explodee:GetPosX(), Explodee:GetPosY(), Explodee:GetPosZ(), false, esPlugin)
|
||||||
|
SendMessageSuccess(Player, Split[2] .. " was successfully exploded")
|
||||||
|
HasExploded = true;
|
||||||
|
return true -- Signalize to MCS that we do not need to call this callback for any more players
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tell MCS to loop through all players and call the callback above with the Player object it has found
|
||||||
|
cRoot:Get():FindAndDoWithPlayer(Split[2], ExplodePlayer)
|
||||||
|
|
||||||
|
if not(HasExploded) then
|
||||||
|
-- We have not broken out so far, therefore, the player must not exist, send failure
|
||||||
|
SendMessageFailure(Player, Split[2] .. " was not found")
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function OnCollectingPickup(Player, Pickup) -- Again, see the API docs for parameters of all hooks. In this case, it is a Player and Pickup object
|
||||||
|
if (Player:GetClientHandle():GetPing() > 100) then -- Get ping of player, in milliseconds
|
||||||
|
return true -- Discriminate against high latency - you don't get drops :D
|
||||||
|
else
|
||||||
|
return false -- You do get the drops! Yay~
|
||||||
|
end
|
||||||
|
end
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Make sure to read the comments for a description of what everything does. Also be sure to return true for all <b>command</b> handlers, unless you want MCS to print out an "Unknown command" message
|
||||||
|
when the command gets executed :P. Make sure to follow standards - use CoreMessaging.lua functions for messaging, dashes for no parameter commands and tildes for vice versa,
|
||||||
|
and finally, <a href="index.html">the API documentation</a> is your friend!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Happy coding ;)
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
prettyPrint();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -30,6 +30,11 @@ pre
|
||||||
{
|
{
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
|
-moz-tab-size: 2;
|
||||||
|
-o-tab-size: 2;
|
||||||
|
-webkit-tab-size: 2;
|
||||||
|
-ms-tab-size: 2;
|
||||||
|
tab-size: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
body
|
body
|
||||||
|
@ -49,6 +54,12 @@ header
|
||||||
font-family: Segoe UI Light, Helvetica;
|
font-family: Segoe UI Light, Helvetica;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
footer
|
||||||
|
{
|
||||||
|
text-align: center;
|
||||||
|
font-family: Segoe UI Light, Helvetica;
|
||||||
|
}
|
||||||
|
|
||||||
#content
|
#content
|
||||||
{
|
{
|
||||||
padding: 0px 25px 25px 25px;
|
padding: 0px 25px 25px 25px;
|
||||||
|
|
|
@ -229,14 +229,100 @@ end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local function WriteArticles(f)
|
||||||
|
f:write([[
|
||||||
|
<a name="articles"><h2>Articles</h2></a>
|
||||||
|
<p>The following articles provide various extra information on plugin development</p>
|
||||||
|
<ul>
|
||||||
|
]]);
|
||||||
|
for i, extra in ipairs(g_APIDesc.ExtraPages) do
|
||||||
|
local SrcFileName = g_PluginFolder .. "/" .. extra.FileName;
|
||||||
|
if (cFile:Exists(SrcFileName)) then
|
||||||
|
local DstFileName = "API/" .. extra.FileName;
|
||||||
|
if (cFile:Exists(DstFileName)) then
|
||||||
|
cFile:Delete(DstFileName);
|
||||||
|
end
|
||||||
|
cFile:Copy(SrcFileName, DstFileName);
|
||||||
|
f:write("<li><a href=\"" .. extra.FileName .. "\">" .. extra.Title .. "</a></li>\n");
|
||||||
|
else
|
||||||
|
f:write("<li>" .. extra.Title .. " <i>(file is missing)</i></li>\n");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
f:write("</ul><hr />");
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local function WriteClasses(f, a_API, a_ClassMenu)
|
||||||
|
f:write([[
|
||||||
|
<a name="classes"><h2>Class index</h2></a>
|
||||||
|
<p>The following classes are available in the MCServer Lua scripting language:
|
||||||
|
<ul>
|
||||||
|
]]);
|
||||||
|
for i, cls in ipairs(a_API) do
|
||||||
|
f:write("<li><a href=\"", cls.Name, ".html\">", cls.Name, "</a></li>\n");
|
||||||
|
WriteHtmlClass(cls, a_API, a_ClassMenu);
|
||||||
|
end
|
||||||
|
f:write([[
|
||||||
|
</ul></p>
|
||||||
|
<hr />
|
||||||
|
]]);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local function WriteHooks(f, a_Hooks, a_UndocumentedHooks, a_HookNav)
|
||||||
|
f:write([[
|
||||||
|
<a name="hooks"><h2>Hooks</h2></a>
|
||||||
|
<p>
|
||||||
|
A plugin can register to be called whenever an "interesting event" occurs. It does so by calling
|
||||||
|
<a href="cPluginManager.html">cPluginManager</a>'s AddHook() function and implementing a callback
|
||||||
|
function to handle the event.</p>
|
||||||
|
<p>
|
||||||
|
A plugin can decide whether it will let the event pass through to the rest of the plugins, or hide it
|
||||||
|
from them. This is determined by the return value from the hook callback function. If the function
|
||||||
|
returns false or no value, the event is propagated further. If the function returns true, the processing
|
||||||
|
is stopped, no other plugin receives the notification (and possibly MCServer disables the default
|
||||||
|
behavior for the event). See each hook's details to see the exact behavior.</p>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Hook name</th>
|
||||||
|
<th>Called when</th>
|
||||||
|
</tr>
|
||||||
|
]]);
|
||||||
|
for i, hook in ipairs(a_Hooks) do
|
||||||
|
if (hook.DefaultFnName == nil) then
|
||||||
|
-- The hook is not documented yet
|
||||||
|
f:write(" <tr>\n <td>" .. hook.Name .. "</td>\n <td><i>(No documentation yet)</i></td>\n </tr>\n");
|
||||||
|
table.insert(a_UndocumentedHooks, hook.Name);
|
||||||
|
else
|
||||||
|
f:write(" <tr>\n <td><a href=\"" .. hook.DefaultFnName .. ".html\">" .. hook.Name .. "</a></td>\n <td>" .. LinkifyString(hook.CalledWhen, hook.Name) .. "</td>\n </tr>\n");
|
||||||
|
WriteHtmlHook(hook, a_HookNav);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
f:write([[
|
||||||
|
</table>
|
||||||
|
<hr />
|
||||||
|
]]);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function DumpAPIHtml()
|
function DumpAPIHtml()
|
||||||
LOG("Dumping all available functions and constants to API subfolder...");
|
LOG("Dumping all available functions and constants to API subfolder...");
|
||||||
|
|
||||||
LOG("Moving static files..");
|
LOG("Copying static files..");
|
||||||
cFile:CreateFolder("API/Static");
|
cFile:CreateFolder("API/Static");
|
||||||
local localFolder = g_Plugin:GetLocalFolder();
|
local localFolder = g_Plugin:GetLocalFolder();
|
||||||
for k, v in cFile:GetFolderContents(localFolder .. "/Static") do
|
for idx, fnam in ipairs(cFile:GetFolderContents(localFolder .. "/Static")) do
|
||||||
cFile:Copy(localFolder .. "/Static/" .. v, "API/Static/" .. v);
|
cFile:Delete("API/Static/" .. fnam);
|
||||||
|
cFile:Copy(localFolder .. "/Static/" .. fnam, "API/Static/" .. fnam);
|
||||||
end
|
end
|
||||||
|
|
||||||
LOG("Creating API tables...");
|
LOG("Creating API tables...");
|
||||||
|
@ -293,7 +379,30 @@ function DumpAPIHtml()
|
||||||
LOGINFO("Cannot output HTML API: " .. err);
|
LOGINFO("Cannot output HTML API: " .. err);
|
||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Create a class navigation menu that will be inserted into each class file for faster navigation (#403)
|
||||||
|
local ClassMenuTab = {};
|
||||||
|
for idx, cls in ipairs(API) do
|
||||||
|
table.insert(ClassMenuTab, "<a href='");
|
||||||
|
table.insert(ClassMenuTab, cls.Name);
|
||||||
|
table.insert(ClassMenuTab, ".html'>");
|
||||||
|
table.insert(ClassMenuTab, cls.Name);
|
||||||
|
table.insert(ClassMenuTab, "</a><br />");
|
||||||
|
end
|
||||||
|
local ClassMenu = table.concat(ClassMenuTab, "");
|
||||||
|
|
||||||
|
-- Create a hook navigation menu that will be inserted into each hook file for faster navigation(#403)
|
||||||
|
local HookNavTab = {};
|
||||||
|
for idx, hook in ipairs(Hooks) do
|
||||||
|
table.insert(HookNavTab, "<a href='");
|
||||||
|
table.insert(HookNavTab, hook.DefaultFnName);
|
||||||
|
table.insert(HookNavTab, ".html'>");
|
||||||
|
table.insert(HookNavTab, (hook.Name:gsub("^HOOK_", ""))); -- remove the "HOOK_" part of the name
|
||||||
|
table.insert(HookNavTab, "</a><br />");
|
||||||
|
end
|
||||||
|
local HookNav = table.concat(HookNavTab, "");
|
||||||
|
|
||||||
|
-- Write the HTML file:
|
||||||
f:write([[<!DOCTYPE html>
|
f:write([[<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -308,79 +417,30 @@ function DumpAPIHtml()
|
||||||
</header>
|
</header>
|
||||||
<p>The API reference is divided into the following sections:</p>
|
<p>The API reference is divided into the following sections:</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li><a href="#articles">Articles</a></li>
|
||||||
<li><a href="#classes">Class index</a></li>
|
<li><a href="#classes">Class index</a></li>
|
||||||
<li><a href="#hooks">Hooks</a></li>
|
<li><a href="#hooks">Hooks</a></li>
|
||||||
<li><a href="#extra">Extra pages</a></li>
|
|
||||||
<li><a href="#docstats">Documentation statistics</a></li>
|
<li><a href="#docstats">Documentation statistics</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr />
|
<hr />
|
||||||
<a name="classes"><h2>Class index</h2></a>
|
|
||||||
<p>The following classes are available in the MCServer Lua scripting language:
|
|
||||||
<ul>
|
|
||||||
]]);
|
]]);
|
||||||
for i, cls in ipairs(API) do
|
|
||||||
f:write("<li><a href=\"", cls.Name, ".html\">", cls.Name, "</a></li>\n");
|
|
||||||
WriteHtmlClass(cls, API);
|
|
||||||
end
|
|
||||||
f:write([[
|
|
||||||
</ul></p>
|
|
||||||
<hr />
|
|
||||||
<a name="hooks"><h2>Hooks</h2></a>
|
|
||||||
<p>
|
|
||||||
A plugin can register to be called whenever an "interesting event" occurs. It does so by calling
|
|
||||||
<a href="cPluginManager.html">cPluginManager</a>'s AddHook() function and implementing a callback
|
|
||||||
function to handle the event.</p>
|
|
||||||
<p>
|
|
||||||
A plugin can decide whether it will let the event pass through to the rest of the plugins, or hide it
|
|
||||||
from them. This is determined by the return value from the hook callback function. If the function
|
|
||||||
returns false or no value, the event is propagated further. If the function returns true, the processing
|
|
||||||
is stopped, no other plugin receives the notification (and possibly MCServer disables the default
|
|
||||||
behavior for the event). See each hook's details to see the exact behavior.</p>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>Hook name</th>
|
|
||||||
<th>Called when</th>
|
|
||||||
</tr>
|
|
||||||
]]);
|
|
||||||
for i, hook in ipairs(Hooks) do
|
|
||||||
if (hook.DefaultFnName == nil) then
|
|
||||||
-- The hook is not documented yet
|
|
||||||
f:write(" <tr>\n <td>" .. hook.Name .. "</td>\n <td><i>(No documentation yet)</i></td>\n </tr>\n");
|
|
||||||
table.insert(UndocumentedHooks, hook.Name);
|
|
||||||
else
|
|
||||||
f:write(" <tr>\n <td><a href=\"" .. hook.DefaultFnName .. ".html\">" .. hook.Name .. "</a></td>\n <td>" .. LinkifyString(hook.CalledWhen, hook.Name) .. "</td>\n </tr>\n");
|
|
||||||
WriteHtmlHook(hook);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
f:write([[ </table>
|
|
||||||
|
|
||||||
<hr />
|
WriteArticles(f);
|
||||||
<a name="extra"><h2>Extra pages</h2></a>
|
WriteClasses(f, API, ClassMenu);
|
||||||
|
WriteHooks(f, Hooks, UndocumentedHooks, HookNav);
|
||||||
<p>The following pages provide various extra information</p>
|
|
||||||
|
-- Copy the static files to the output folder:
|
||||||
<ul>
|
local StaticFiles =
|
||||||
]]);
|
{
|
||||||
for i, extra in ipairs(g_APIDesc.ExtraPages) do
|
"main.css",
|
||||||
local SrcFileName = g_PluginFolder .. "/" .. extra.FileName;
|
"prettify.js",
|
||||||
if (cFile:Exists(SrcFileName)) then
|
"prettify.css",
|
||||||
local DstFileName = "API/" .. extra.FileName;
|
"lang-lua.js",
|
||||||
if (cFile:Exists(DstFileName)) then
|
};
|
||||||
cFile:Delete(DstFileName);
|
for idx, fnam in ipairs(StaticFiles) do
|
||||||
end
|
cFile:Delete("API/" .. fnam);
|
||||||
cFile:Copy(SrcFileName, DstFileName);
|
cFile:Copy(g_Plugin:GetLocalFolder() .. "/" .. fnam, "API/" .. fnam);
|
||||||
f:write(" <li><a href=\"" .. extra.FileName .. "\">" .. extra.Title .. "</a></li>\n");
|
|
||||||
else
|
|
||||||
f:write(" <li>" .. extra.Title .. " <i>(file is missing)</i></li>\n");
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
f:write("</ul>");
|
|
||||||
|
|
||||||
-- Copy the static files to the output folder (overwrite any existing):
|
|
||||||
cFile:Copy(g_Plugin:GetLocalFolder() .. "/main.css", "API/main.css");
|
|
||||||
cFile:Copy(g_Plugin:GetLocalFolder() .. "/prettify.js", "API/prettify.js");
|
|
||||||
cFile:Copy(g_Plugin:GetLocalFolder() .. "/prettify.css", "API/prettify.css");
|
|
||||||
cFile:Copy(g_Plugin:GetLocalFolder() .. "/lang-lua.js", "API/lang-lua.js");
|
|
||||||
|
|
||||||
-- List the documentation problems:
|
-- List the documentation problems:
|
||||||
LOG("Listing leftovers...");
|
LOG("Listing leftovers...");
|
||||||
|
@ -831,7 +891,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function WriteHtmlClass(a_ClassAPI, a_AllAPI)
|
function WriteHtmlClass(a_ClassAPI, a_AllAPI, a_ClassMenu)
|
||||||
local cf, err = io.open("API/" .. a_ClassAPI.Name .. ".html", "w");
|
local cf, err = io.open("API/" .. a_ClassAPI.Name .. ".html", "w");
|
||||||
if (cf == nil) then
|
if (cf == nil) then
|
||||||
return;
|
return;
|
||||||
|
@ -946,7 +1006,17 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI)
|
||||||
<h1>]], a_ClassAPI.Name, [[</h1>
|
<h1>]], a_ClassAPI.Name, [[</h1>
|
||||||
<hr />
|
<hr />
|
||||||
</header>
|
</header>
|
||||||
<h1>Contents</h1>
|
<table><tr><td style="vertical-align: top;">
|
||||||
|
Index:<br />
|
||||||
|
<a href='index.html#articles'>Articles</a><br />
|
||||||
|
<a href='index.html#classes'>Classes</a><br />
|
||||||
|
<a href='index.html#hooks'>Hooks</a><br />
|
||||||
|
<br />
|
||||||
|
Quick navigation:<br />
|
||||||
|
]]);
|
||||||
|
cf:write(a_ClassMenu);
|
||||||
|
cf:write([[
|
||||||
|
</td><td style="vertical-align: top;"><h1>Contents</h1>
|
||||||
<p><ul>
|
<p><ul>
|
||||||
]]);
|
]]);
|
||||||
|
|
||||||
|
@ -1044,7 +1114,7 @@ function WriteHtmlClass(a_ClassAPI, a_AllAPI)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
cf:write([[</div><script>prettyPrint();</script></body></html>]]);
|
cf:write([[</td></tr></table></div><script>prettyPrint();</script></body></html>]]);
|
||||||
cf:close();
|
cf:close();
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1052,7 +1122,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function WriteHtmlHook(a_Hook)
|
function WriteHtmlHook(a_Hook, a_HookNav)
|
||||||
local fnam = "API/" .. a_Hook.DefaultFnName .. ".html";
|
local fnam = "API/" .. a_Hook.DefaultFnName .. ".html";
|
||||||
local f, error = io.open(fnam, "w");
|
local f, error = io.open(fnam, "w");
|
||||||
if (f == nil) then
|
if (f == nil) then
|
||||||
|
@ -1075,7 +1145,17 @@ function WriteHtmlHook(a_Hook)
|
||||||
<h1>]], a_Hook.Name, [[</h1>
|
<h1>]], a_Hook.Name, [[</h1>
|
||||||
<hr />
|
<hr />
|
||||||
</header>
|
</header>
|
||||||
<p>
|
<table><tr><td style="vertical-align: top;">
|
||||||
|
Index:<br />
|
||||||
|
<a href='index.html#articles'>Articles</a><br />
|
||||||
|
<a href='index.html#classes'>Classes</a><br />
|
||||||
|
<a href='index.html#hooks'>Hooks</a><br />
|
||||||
|
<br />
|
||||||
|
Quick navigation:<br />
|
||||||
|
]]);
|
||||||
|
f:write(a_HookNav);
|
||||||
|
f:write([[
|
||||||
|
</td><td style="vertical-align: top;"><p>
|
||||||
]]);
|
]]);
|
||||||
f:write(LinkifyString(a_Hook.Desc, HookName));
|
f:write(LinkifyString(a_Hook.Desc, HookName));
|
||||||
f:write("</p>\n<hr /><h1>Callback function</h1>\n<p>The default name for the callback function is ");
|
f:write("</p>\n<hr /><h1>Callback function</h1>\n<p>The default name for the callback function is ");
|
||||||
|
@ -1105,7 +1185,7 @@ function WriteHtmlHook(a_Hook)
|
||||||
f:write("<p>", (example.Desc or "<i>missing Desc</i>"), "</p>\n");
|
f:write("<p>", (example.Desc or "<i>missing Desc</i>"), "</p>\n");
|
||||||
f:write("<pre class=\"prettyprint lang-lua\">", (example.Code or "<i>missing Code</i>"), "\n</pre>\n\n");
|
f:write("<pre class=\"prettyprint lang-lua\">", (example.Code or "<i>missing Code</i>"), "\n</pre>\n\n");
|
||||||
end
|
end
|
||||||
f:write([[</div><script>prettyPrint();</script></body></html>]]);
|
f:write([[</td></tr></table></div><script>prettyPrint();</script></body></html>]]);
|
||||||
f:close();
|
f:close();
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ function Initialize(Plugin)
|
||||||
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_RIGHT_CLICKING_ENTITY, OnPlayerRightClickingEntity);
|
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_RIGHT_CLICKING_ENTITY, OnPlayerRightClickingEntity);
|
||||||
cPluginManager.AddHook(cPluginManager.HOOK_WORLD_TICK, OnWorldTick);
|
cPluginManager.AddHook(cPluginManager.HOOK_WORLD_TICK, OnWorldTick);
|
||||||
cPluginManager.AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
|
cPluginManager.AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
|
||||||
|
cPluginManager.AddHook(cPluginManager.HOOK_PLUGINS_LOADED, OnPluginsLoaded);
|
||||||
|
|
||||||
PM = cRoot:Get():GetPluginManager();
|
PM = cRoot:Get():GetPluginManager();
|
||||||
PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities");
|
PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities");
|
||||||
|
@ -524,6 +525,14 @@ end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function OnPluginsLoaded()
|
||||||
|
LOG("All plugins loaded");
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function OnChunkGenerated(a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc)
|
function OnChunkGenerated(a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc)
|
||||||
-- Get the topmost block coord:
|
-- Get the topmost block coord:
|
||||||
local Height = a_ChunkDesc:GetHeight(0, 0);
|
local Height = a_ChunkDesc:GetHeight(0, 0);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
local Carpets = {}
|
local Carpets = {}
|
||||||
|
local PLUGIN
|
||||||
|
|
||||||
function Initialize( Plugin )
|
function Initialize( Plugin )
|
||||||
Plugin:SetName( "MagicCarpet" )
|
Plugin:SetName( "MagicCarpet" )
|
||||||
|
@ -9,7 +10,9 @@ function Initialize( Plugin )
|
||||||
|
|
||||||
local PluginManager = cPluginManager:Get()
|
local PluginManager = cPluginManager:Get()
|
||||||
PluginManager:BindCommand("/mc", "magiccarpet", HandleCarpetCommand, " - Spawns a magical carpet");
|
PluginManager:BindCommand("/mc", "magiccarpet", HandleCarpetCommand, " - Spawns a magical carpet");
|
||||||
|
|
||||||
|
PLUGIN = Plugin
|
||||||
|
|
||||||
LOG( "Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() )
|
LOG( "Initialised " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() )
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
@ -75,4 +78,4 @@ function OnPlayerMoving(Player)
|
||||||
end
|
end
|
||||||
Carpet:moveTo( cLocation:new( Player:GetPosX(), Player:GetPosY(), Player:GetPosZ() ) )
|
Carpet:moveTo( cLocation:new( Player:GetPosX(), Player:GetPosY(), Player:GetPosZ() ) )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,7 +38,7 @@ cd ..
|
||||||
|
|
||||||
:: Upload the API to the web:
|
:: Upload the API to the web:
|
||||||
|
|
||||||
ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% /LuaAPI MCServer/API/*.*
|
ncftpput -p %ftppass% -u %ftpuser% -T temp_ -R %ftpsite% /LuaAPI MCServer/API/*.*
|
||||||
if errorlevel 1 goto haderror
|
if errorlevel 1 goto haderror
|
||||||
echo Upload finished.
|
echo Upload finished.
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,23 @@ if %vc%a == a set vc="vcbuild.exe"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
:: Check that the required environment vars are available:
|
||||||
|
if "a%ftppass%" == "a" (
|
||||||
|
echo You need to set FTP password in the ftppass environment variable to upload the files
|
||||||
|
goto haderror
|
||||||
|
)
|
||||||
|
if "a%ftpuser%" == "a" (
|
||||||
|
echo You need to set FTP username in the ftpuser environment variable to upload the files
|
||||||
|
goto haderror
|
||||||
|
)
|
||||||
|
if "a%ftpsite%" == "a" (
|
||||||
|
echo You need to set FTP server in the ftpsite environment variable to upload the files
|
||||||
|
goto haderror
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
:: Get the date and time into vars:
|
:: Get the date and time into vars:
|
||||||
For /f "tokens=2-4 delims=/. " %%a in ('date /t') do (
|
For /f "tokens=2-4 delims=/. " %%a in ('date /t') do (
|
||||||
set MYYEAR=%%c
|
set MYYEAR=%%c
|
||||||
|
@ -34,11 +51,6 @@ For /f "tokens=2-4 delims=/. " %%a in ('date /t') do (
|
||||||
)
|
)
|
||||||
For /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set MYTIME=%%a_%%b)
|
For /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set MYTIME=%%a_%%b)
|
||||||
|
|
||||||
echo MYYEAR = %MYYEAR%
|
|
||||||
echo MYMONTH = %MYMONTH%
|
|
||||||
echo MYDAY = %MYDAY%
|
|
||||||
echo MYTIME = %MYTIME%
|
|
||||||
|
|
||||||
echo Performing nightbuild of MC-Server
|
echo Performing nightbuild of MC-Server
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,9 +60,6 @@ echo Performing nightbuild of MC-Server
|
||||||
set DONOTPAUSE=y
|
set DONOTPAUSE=y
|
||||||
|
|
||||||
:: Update the sources to the latest revision:
|
:: Update the sources to the latest revision:
|
||||||
del src\Bindings\Bindings.cpp
|
|
||||||
del src\Bindings\Bindings.h
|
|
||||||
git checkout -- src\Bindings\Bindings.*
|
|
||||||
git pull
|
git pull
|
||||||
if errorlevel 1 goto haderror
|
if errorlevel 1 goto haderror
|
||||||
|
|
||||||
|
@ -72,7 +81,9 @@ if errorlevel 1 goto haderror
|
||||||
|
|
||||||
|
|
||||||
:: Test if the version is already present, using a "tagfile" that we create upon successful build
|
:: Test if the version is already present, using a "tagfile" that we create upon successful build
|
||||||
set TAGFILE=Install\built_%COMMITID%.tag
|
set TAGFOLDER=Install\%MYYEAR%_%MYMONTH%\
|
||||||
|
set TAGFILE=%TAGFOLDER%built_%COMMITID%.tag
|
||||||
|
echo Tag file: %TAGFILE%
|
||||||
if exist %TAGFILE% (
|
if exist %TAGFILE% (
|
||||||
echo Latest version already present, bailing out
|
echo Latest version already present, bailing out
|
||||||
goto end
|
goto end
|
||||||
|
@ -81,13 +92,13 @@ if exist %TAGFILE% (
|
||||||
|
|
||||||
|
|
||||||
:: Update the Bindings:
|
:: Update the Bindings:
|
||||||
del src\Bindings.cpp
|
|
||||||
del src\Bindings.h
|
|
||||||
echo Updating Lua bindings
|
echo Updating Lua bindings
|
||||||
|
del src\Bindings\Bindings.cpp
|
||||||
|
del src\Bindings\Bindings.h
|
||||||
set ALLTOLUA_WAIT=N
|
set ALLTOLUA_WAIT=N
|
||||||
cd src
|
cd src\Bindings
|
||||||
call AllToLua.bat
|
call AllToLua.bat
|
||||||
cd ..
|
cd ..\..
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,18 +137,6 @@ if errorlevel 1 goto haderror
|
||||||
|
|
||||||
:: upload to the FTP:
|
:: upload to the FTP:
|
||||||
:upload
|
:upload
|
||||||
if "a%ftppass%" == "a" (
|
|
||||||
echo You need to set FTP password in the ftppass environment variable to upload the files
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
if "a%ftpuser%" == "a" (
|
|
||||||
echo You need to set FTP username in the ftpuser environment variable to upload the files
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
if "a%ftpsite%" == "a" (
|
|
||||||
echo You need to set FTP server in the ftpsite environment variable to upload the files
|
|
||||||
goto end
|
|
||||||
)
|
|
||||||
ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% / Install\MCServer_Win_%FILESUFFIX%.7z
|
ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% / Install\MCServer_Win_%FILESUFFIX%.7z
|
||||||
if errorlevel 1 goto haderror
|
if errorlevel 1 goto haderror
|
||||||
ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% /PDBs Install\PDBs_%FILESUFFIX%.7z
|
ncftpput -p %ftppass% -u %ftpuser% -T temp_ %ftpsite% /PDBs Install\PDBs_%FILESUFFIX%.7z
|
||||||
|
@ -148,6 +147,7 @@ echo Upload finished.
|
||||||
|
|
||||||
|
|
||||||
:: Create the tagfile so that we know that this CommitID has been built already
|
:: Create the tagfile so that we know that this CommitID has been built already
|
||||||
|
mkdir %TAGFOLDER%
|
||||||
touch %TAGFILE%
|
touch %TAGFILE%
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ After you've cloned the repository, you probably want to pull down the submodule
|
||||||
|
|
||||||
Compilation instructions are available in the COMPILING file.
|
Compilation instructions are available in the COMPILING file.
|
||||||
|
|
||||||
Linux builds can be downloaded from [the Berboe CI server](http://ci.berboe.co.uk) and windows from xoft's [nightly build service](http://mc-server.xoft.cz).
|
Linux builds can be downloaded from [Bearbin's CI Service](http://ci.bearbin.net) and Windows builds from xoft's [nightly build service](http://mc-server.xoft.cz).
|
||||||
|
|
||||||
After you've extracted the files, simply run the MCServer executable.
|
After you've extracted the files, simply run the MCServer executable.
|
||||||
|
|
||||||
|
|
24
clean.bat
24
clean.bat
|
@ -1,24 +0,0 @@
|
||||||
del *.ncb
|
|
||||||
del *.ilk
|
|
||||||
del *.lib
|
|
||||||
del *.exp
|
|
||||||
del *.map
|
|
||||||
del *.pdb
|
|
||||||
del log.txt
|
|
||||||
del *.bsc
|
|
||||||
del applog.txt
|
|
||||||
del *.suo /AH
|
|
||||||
del *.user
|
|
||||||
del debug\*.* /Q
|
|
||||||
del release\*.* /Q
|
|
||||||
rd release /Q
|
|
||||||
rd debug /Q
|
|
||||||
|
|
||||||
cd MCServer
|
|
||||||
del MCServer.exe
|
|
||||||
del MCServer_debug.exe
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd VC2010
|
|
||||||
call clean.bat
|
|
||||||
cd ..
|
|
|
@ -1,27 +1,13 @@
|
||||||
CryptoPP
|
lib
|
||||||
expat
|
Tools
|
||||||
jsoncpp-src-0.5.0
|
Tests
|
||||||
lua-5.1.4
|
src/Bindings.cpp
|
||||||
MemDumpAnalysis/expat
|
src/Bindings.h
|
||||||
source/LuaExpat
|
src/LeakFinder.cpp
|
||||||
source/SQLite
|
src/LeakFinder.h
|
||||||
squirrel_3_0_1_stable
|
src/StackWalker.cpp
|
||||||
VC2008/CryptoPP.vcproj
|
src/StackWalker.h
|
||||||
zlib-1.2.5
|
|
||||||
zlib-1.2.7
|
|
||||||
source/Bindings.cpp
|
|
||||||
source/Bindings.h
|
|
||||||
source/LeakFinder.cpp
|
|
||||||
source/LeakFinder.h
|
|
||||||
source/StackWalker.cpp
|
|
||||||
source/StackWalker.h
|
|
||||||
BiomeVisualiser/BiomeVisualiser.vcproj
|
|
||||||
MemDumpAnalysis/MemDumpAnalysis.vcproj
|
|
||||||
ProtoProxy/ProtoProxy.vcproj
|
|
||||||
Tests/NoiseTest/NoiseTest.vcproj
|
|
||||||
Tools/BlockZapper/BlockZapper.vcproj
|
|
||||||
Tools/ToLuaDoxy/ToLuaDoxy.vcproj
|
|
||||||
VC2008
|
VC2008
|
||||||
|
VC2013
|
||||||
Install
|
Install
|
||||||
log.xml
|
build
|
||||||
build
|
|
||||||
|
|
|
@ -2,10 +2,15 @@
|
||||||
cmake_minimum_required (VERSION 2.6)
|
cmake_minimum_required (VERSION 2.6)
|
||||||
project (expat)
|
project (expat)
|
||||||
|
|
||||||
include_directories ("${PROJECT_SOURCE_DIR}/../../src/")
|
|
||||||
|
|
||||||
file(GLOB SOURCE
|
file(GLOB SOURCE
|
||||||
"*.c"
|
"*.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# add headers to MSVC project files:
|
||||||
|
if (WIN32)
|
||||||
|
file(GLOB HEADERS "*.h")
|
||||||
|
set(SOURCE ${SOURCE} ${HEADERS})
|
||||||
|
source_group("Sources" FILES ${SOURCE})
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(expat ${SOURCE})
|
add_library(expat ${SOURCE})
|
||||||
|
|
|
@ -8,12 +8,23 @@ file(GLOB SOURCE
|
||||||
"src/*.c"
|
"src/*.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(${STATIC_LUA})
|
list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/src/lua.c" "${PROJECT_SOURCE_DIR}/src/luac.c")
|
||||||
add_library(lua ${SOURCE})
|
|
||||||
else()
|
# add headers to MSVC project files:
|
||||||
add_library(lua SHARED ${SOURCE})
|
if (WIN32)
|
||||||
|
file(GLOB HEADERS "src/*.h")
|
||||||
|
list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/src/lua.h" "${PROJECT_SOURCE_DIR}/src/luac.h")
|
||||||
|
set(SOURCE ${SOURCE} ${HEADERS})
|
||||||
|
source_group("Sources" FILES ${SOURCE})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(UNIX)
|
# Lua needs to be linked dynamically on Windows and statically on *nix, so that LuaRocks work
|
||||||
target_link_libraries(lua m dl)
|
if (WIN32)
|
||||||
|
add_library(lua SHARED ${SOURCE})
|
||||||
|
else()
|
||||||
|
add_library(lua ${SOURCE})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (UNIX)
|
||||||
|
target_link_libraries(lua m dl)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -2,13 +2,24 @@
|
||||||
cmake_minimum_required (VERSION 2.6)
|
cmake_minimum_required (VERSION 2.6)
|
||||||
project (sqlite)
|
project (sqlite)
|
||||||
|
|
||||||
include_directories ("${PROJECT_SOURCE_DIR}/../../src/")
|
|
||||||
include_directories ("${PROJECT_SOURCE_DIR}/../")
|
include_directories ("${PROJECT_SOURCE_DIR}/../")
|
||||||
|
|
||||||
file(GLOB SOURCE
|
file(GLOB SOURCE
|
||||||
"*.c"
|
"*.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# add headers to MSVC project files:
|
||||||
|
if (WIN32)
|
||||||
|
file(GLOB HEADERS "src/*.h")
|
||||||
|
list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/src/lua.h" "${PROJECT_SOURCE_DIR}/src/luac.h")
|
||||||
|
set(SOURCE ${SOURCE} ${HEADERS})
|
||||||
|
source_group("Sources" FILES ${SOURCE})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
add_library(sqlite ${SOURCE})
|
add_library(sqlite ${SOURCE})
|
||||||
|
|
||||||
target_link_libraries(sqlite dl)
|
if (UNIX)
|
||||||
|
target_link_libraries(sqlite dl)
|
||||||
|
endif()
|
||||||
|
|
|
@ -1,17 +1,8 @@
|
||||||
|
|
||||||
:: AllToLua.bat
|
:: AllToLua.bat
|
||||||
|
|
||||||
:: This scripts updates the automatically-generates Lua bindings in Bindings.cpp / Bindings.h
|
:: This scripts updates the automatically-generates Lua bindings in Bindings.cpp / Bindings.h
|
||||||
|
:: When called without any parameters, it will pause for a keypress at the end
|
||||||
|
:: Call with any parameter to disable the wait (for buildserver use)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
:: If there was a Git conflict, resolve it by resetting to HEAD; we're regenerating the files from scratch anyway
|
|
||||||
git checkout --ours Bindings.cpp
|
|
||||||
git add -u Bindings.cpp
|
|
||||||
git checkout --ours Bindings.h
|
|
||||||
git add -u Bindings.h
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,5 +14,9 @@ git add -u Bindings.h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
: Wait for keypress, if no param given:
|
||||||
if %ALLTOLUA_WAIT%N == N pause
|
if %ALLTOLUA_WAIT%N == N pause
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ extern "C"
|
||||||
// fwd: SQLite/lsqlite3.c
|
// fwd: SQLite/lsqlite3.c
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
LUALIB_API int luaopen_lsqlite3(lua_State * L);
|
int luaopen_lsqlite3(lua_State * L);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fwd: LuaExpat/lxplib.c:
|
// fwd: LuaExpat/lxplib.c:
|
||||||
|
@ -309,7 +309,7 @@ void cLuaState::Push(const AStringVector & a_Vector)
|
||||||
{
|
{
|
||||||
ASSERT(IsValid());
|
ASSERT(IsValid());
|
||||||
|
|
||||||
lua_createtable(m_LuaState, a_Vector.size(), 0);
|
lua_createtable(m_LuaState, (int)a_Vector.size(), 0);
|
||||||
int newTable = lua_gettop(m_LuaState);
|
int newTable = lua_gettop(m_LuaState);
|
||||||
int index = 1;
|
int index = 1;
|
||||||
for (AStringVector::const_iterator itr = a_Vector.begin(), end = a_Vector.end(); itr != end; ++itr, ++index)
|
for (AStringVector::const_iterator itr = a_Vector.begin(), end = a_Vector.end(); itr != end; ++itr, ++index)
|
||||||
|
|
|
@ -240,6 +240,25 @@ public:
|
||||||
return CallFunction(0);
|
return CallFunction(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call any 0-param 1-return Lua function in a single line:
|
||||||
|
template<
|
||||||
|
typename FnT, typename RetT1
|
||||||
|
>
|
||||||
|
bool Call(FnT a_FnName, const cRet & a_Mark, RetT1 & a_Ret1)
|
||||||
|
{
|
||||||
|
if (!PushFunction(a_FnName))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!CallFunction(1))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GetReturn(-1, a_Ret1);
|
||||||
|
lua_pop(m_LuaState, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Call any 1-param 1-return Lua function in a single line:
|
/// Call any 1-param 1-return Lua function in a single line:
|
||||||
template<
|
template<
|
||||||
typename FnT, typename ArgT1, typename RetT1
|
typename FnT, typename ArgT1, typename RetT1
|
||||||
|
|
|
@ -82,6 +82,7 @@ public:
|
||||||
virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0;
|
virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0;
|
||||||
virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
|
virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
|
||||||
virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0;
|
virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0;
|
||||||
|
virtual bool OnPluginsLoaded (void) = 0;
|
||||||
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
|
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
|
||||||
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
|
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
|
||||||
virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0;
|
virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0;
|
||||||
|
|
|
@ -386,7 +386,7 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can
|
||||||
{
|
{
|
||||||
case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
|
case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
|
||||||
case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res); break;
|
case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res); break;
|
||||||
case esCreeper: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res); break;
|
case esMonster: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cMonster *)a_SourceData, cLuaState::Return, res); break;
|
||||||
case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break;
|
case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break;
|
||||||
case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break;
|
case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break;
|
||||||
case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
|
case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
|
||||||
|
@ -910,6 +910,24 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cPluginLua::OnPluginsLoaded(void)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CriticalSection);
|
||||||
|
bool res = false;
|
||||||
|
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED];
|
||||||
|
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
m_LuaState.Call((int)(**itr), cLuaState::Return, ret);
|
||||||
|
res = res || ret;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cPluginLua::OnPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe)
|
bool cPluginLua::OnPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CriticalSection);
|
cCSLock Lock(m_CriticalSection);
|
||||||
|
|
|
@ -79,6 +79,7 @@ public:
|
||||||
virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
|
virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
|
||||||
virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
|
virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
|
||||||
virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
|
virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
|
||||||
|
virtual bool OnPluginsLoaded (void) override;
|
||||||
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
|
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
|
||||||
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
|
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
|
||||||
virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override;
|
virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override;
|
||||||
|
|
|
@ -118,7 +118,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni)
|
||||||
int KeyNum = a_SettingsIni.FindKey("Plugins");
|
int KeyNum = a_SettingsIni.FindKey("Plugins");
|
||||||
|
|
||||||
// If it does, how many plugins are there?
|
// If it does, how many plugins are there?
|
||||||
unsigned int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0);
|
int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0);
|
||||||
|
|
||||||
if (KeyNum == -1)
|
if (KeyNum == -1)
|
||||||
{
|
{
|
||||||
|
@ -126,7 +126,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni)
|
||||||
}
|
}
|
||||||
else if (NumPlugins > 0)
|
else if (NumPlugins > 0)
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < NumPlugins; i++)
|
for (int i = 0; i < NumPlugins; i++)
|
||||||
{
|
{
|
||||||
AString ValueName = a_SettingsIni.GetValueName(KeyNum, i);
|
AString ValueName = a_SettingsIni.GetValueName(KeyNum, i);
|
||||||
if (ValueName.compare("Plugin") == 0)
|
if (ValueName.compare("Plugin") == 0)
|
||||||
|
@ -136,7 +136,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni)
|
||||||
{
|
{
|
||||||
if (m_Plugins.find(PluginFile) != m_Plugins.end())
|
if (m_Plugins.find(PluginFile) != m_Plugins.end())
|
||||||
{
|
{
|
||||||
LoadPlugin( PluginFile );
|
LoadPlugin(PluginFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,6 +155,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni)
|
||||||
{
|
{
|
||||||
LOG("-- Loaded 1 Plugin --");
|
LOG("-- Loaded 1 Plugin --");
|
||||||
}
|
}
|
||||||
|
CallHookPluginsLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -987,6 +988,25 @@ bool cPluginManager::CallHookPlayerUsingItem(cPlayer & a_Player, int a_BlockX, i
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cPluginManager::CallHookPluginsLoaded(void)
|
||||||
|
{
|
||||||
|
HookMap::iterator Plugins = m_Hooks.find(HOOK_PLUGINS_LOADED);
|
||||||
|
if (Plugins == m_Hooks.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool res = false;
|
||||||
|
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
|
||||||
|
{
|
||||||
|
res = !(*itr)->OnPluginsLoaded() || res;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cPluginManager::CallHookPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe)
|
bool cPluginManager::CallHookPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe)
|
||||||
{
|
{
|
||||||
HookMap::iterator Plugins = m_Hooks.find(HOOK_POST_CRAFTING);
|
HookMap::iterator Plugins = m_Hooks.find(HOOK_POST_CRAFTING);
|
||||||
|
|
|
@ -94,6 +94,7 @@ public: // tolua_export
|
||||||
HOOK_PLAYER_USED_ITEM,
|
HOOK_PLAYER_USED_ITEM,
|
||||||
HOOK_PLAYER_USING_BLOCK,
|
HOOK_PLAYER_USING_BLOCK,
|
||||||
HOOK_PLAYER_USING_ITEM,
|
HOOK_PLAYER_USING_ITEM,
|
||||||
|
HOOK_PLUGINS_LOADED,
|
||||||
HOOK_POST_CRAFTING,
|
HOOK_POST_CRAFTING,
|
||||||
HOOK_PRE_CRAFTING,
|
HOOK_PRE_CRAFTING,
|
||||||
HOOK_SPAWNED_ENTITY,
|
HOOK_SPAWNED_ENTITY,
|
||||||
|
@ -181,6 +182,7 @@ public: // tolua_export
|
||||||
bool CallHookPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
|
bool CallHookPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
|
||||||
bool CallHookPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
bool CallHookPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||||
bool CallHookPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
|
bool CallHookPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ);
|
||||||
|
bool CallHookPluginsLoaded (void);
|
||||||
bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
|
bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
|
||||||
bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
|
bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
|
||||||
bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity);
|
bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity);
|
||||||
|
|
|
@ -301,10 +301,10 @@ bool cBlockArea::Read(cWorld * a_World, int a_MinBlockX, int a_MaxBlockX, int a_
|
||||||
LOGWARNING("%s: MaxBlockY less than zero, adjusting to zero", __FUNCTION__);
|
LOGWARNING("%s: MaxBlockY less than zero, adjusting to zero", __FUNCTION__);
|
||||||
a_MaxBlockY = 0;
|
a_MaxBlockY = 0;
|
||||||
}
|
}
|
||||||
else if (a_MaxBlockY >= cChunkDef::Height)
|
else if (a_MaxBlockY > cChunkDef::Height)
|
||||||
{
|
{
|
||||||
LOGWARNING("%s: MaxBlockY more than chunk height, adjusting to chunk height", __FUNCTION__);
|
LOGWARNING("%s: MaxBlockY more than chunk height, adjusting to chunk height", __FUNCTION__);
|
||||||
a_MaxBlockY = cChunkDef::Height - 1;
|
a_MaxBlockY = cChunkDef::Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the needed memory:
|
// Allocate the needed memory:
|
||||||
|
@ -349,10 +349,10 @@ bool cBlockArea::Write(cWorld * a_World, int a_MinBlockX, int a_MinBlockY, int a
|
||||||
LOGWARNING("%s: MinBlockY less than zero, adjusting to zero", __FUNCTION__);
|
LOGWARNING("%s: MinBlockY less than zero, adjusting to zero", __FUNCTION__);
|
||||||
a_MinBlockY = 0;
|
a_MinBlockY = 0;
|
||||||
}
|
}
|
||||||
else if (a_MinBlockY >= cChunkDef::Height - m_SizeY)
|
else if (a_MinBlockY > cChunkDef::Height - m_SizeY)
|
||||||
{
|
{
|
||||||
LOGWARNING("%s: MinBlockY + m_SizeY more than chunk height, adjusting to chunk height", __FUNCTION__);
|
LOGWARNING("%s: MinBlockY + m_SizeY more than chunk height, adjusting to chunk height", __FUNCTION__);
|
||||||
a_MinBlockY = cChunkDef::Height - m_SizeY - 1;
|
a_MinBlockY = cChunkDef::Height - m_SizeY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return a_World->WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes);
|
return a_World->WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes);
|
||||||
|
|
|
@ -833,14 +833,17 @@ enum eExplosionSource
|
||||||
{
|
{
|
||||||
esOther,
|
esOther,
|
||||||
esPrimedTNT,
|
esPrimedTNT,
|
||||||
esCreeper,
|
esMonster,
|
||||||
esBed,
|
esBed,
|
||||||
esEnderCrystal,
|
esEnderCrystal,
|
||||||
esGhastFireball,
|
esGhastFireball,
|
||||||
esWitherSkullBlack,
|
esWitherSkullBlack,
|
||||||
esWitherSkullBlue,
|
esWitherSkullBlue,
|
||||||
esWitherBirth,
|
esWitherBirth,
|
||||||
esPlugin
|
esPlugin,
|
||||||
|
|
||||||
|
// Obsolete constants, kept for compatibility, will be removed after some time:
|
||||||
|
esCreeper = esMonster,
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
if (
|
if (
|
||||||
a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) &&
|
a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) &&
|
||||||
(BlockType != E_BLOCK_AIR)
|
(g_BlockIsSolid[BlockType])
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -13,6 +13,70 @@ public:
|
||||||
: cBlockHandler(a_BlockType)
|
: cBlockHandler(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void OnPlacedByPlayer(cWorld * a_World, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
|
||||||
|
{
|
||||||
|
// Check whether the pumpkin is a part of a golem or a snowman
|
||||||
|
|
||||||
|
if (a_BlockY < 2)
|
||||||
|
{
|
||||||
|
// The pumpkin is too low for a golem / snowman
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCKTYPE BlockY1 = a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
|
||||||
|
BLOCKTYPE BlockY2 = a_World->GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ);
|
||||||
|
|
||||||
|
// Check for a snow golem:
|
||||||
|
if ((BlockY1 == E_BLOCK_SNOW_BLOCK) && (BlockY2 == E_BLOCK_SNOW_BLOCK))
|
||||||
|
{
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtSnowGolem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for an iron golem. First check only the body and legs, since those are the same for both orientations:
|
||||||
|
if ((BlockY1 != E_BLOCK_IRON_BLOCK) || (BlockY2 != E_BLOCK_IRON_BLOCK))
|
||||||
|
{
|
||||||
|
// One of the blocks is not an iron, no chance of a golem here
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check both orientations for hands:
|
||||||
|
if (
|
||||||
|
(a_World->GetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ) == E_BLOCK_IRON_BLOCK) &&
|
||||||
|
(a_World->GetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ) == E_BLOCK_IRON_BLOCK)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Remove the iron blocks:
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
a_World->FastSetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
a_World->FastSetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
|
||||||
|
// Spawn the golem:
|
||||||
|
a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtIronGolem);
|
||||||
|
}
|
||||||
|
else if (
|
||||||
|
(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1) == E_BLOCK_IRON_BLOCK) &&
|
||||||
|
(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1) == E_BLOCK_IRON_BLOCK)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Remove the iron blocks:
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1, E_BLOCK_AIR, 0);
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1, E_BLOCK_AIR, 0);
|
||||||
|
a_World->FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
|
||||||
|
|
||||||
|
// Spawn the golem:
|
||||||
|
a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtIronGolem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
|
|
|
@ -43,6 +43,40 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void OnPlaced(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
|
||||||
|
{
|
||||||
|
super::OnPlaced(a_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
|
||||||
|
|
||||||
|
// Alert diagonal rails
|
||||||
|
OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY + 1, a_BlockZ);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY + 1, a_BlockZ);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ + 1);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ - 1);
|
||||||
|
|
||||||
|
OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY - 1, a_BlockZ);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY - 1, a_BlockZ);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ + 1);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void OnDestroyed(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override
|
||||||
|
{
|
||||||
|
super::OnDestroyed(a_World, a_BlockX, a_BlockY, a_BlockZ);
|
||||||
|
|
||||||
|
// Alert diagonal rails
|
||||||
|
OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY + 1, a_BlockZ);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY + 1, a_BlockZ);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ + 1);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ - 1);
|
||||||
|
|
||||||
|
OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY - 1, a_BlockZ);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY - 1, a_BlockZ);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ + 1);
|
||||||
|
OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void OnNeighborChanged(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override
|
virtual void OnNeighborChanged(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
NIBBLETYPE Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
||||||
|
|
|
@ -12,72 +12,81 @@ include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")
|
||||||
set(FOLDERS OSSupport HTTPServer Bindings Items Blocks Protocol Generating)
|
set(FOLDERS OSSupport HTTPServer Bindings Items Blocks Protocol Generating)
|
||||||
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities)
|
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities)
|
||||||
|
|
||||||
if(NOT WIN32)
|
|
||||||
|
|
||||||
foreach(folder ${FOLDERS})
|
|
||||||
add_subdirectory(${folder})
|
|
||||||
endforeach(folder)
|
|
||||||
|
|
||||||
file(GLOB SOURCE
|
if (NOT WIN32)
|
||||||
"*.cpp"
|
foreach(folder ${FOLDERS})
|
||||||
)
|
add_subdirectory(${folder})
|
||||||
else()
|
endforeach(folder)
|
||||||
|
|
||||||
function(includefolder PATH)
|
file(GLOB SOURCE
|
||||||
FILE(GLOB FOLDER_FILES
|
"*.cpp"
|
||||||
"${PATH}/*.cpp"
|
|
||||||
"${PATH}/*.h"
|
|
||||||
)
|
)
|
||||||
source_group("${PATH}" FILES ${FOLDER_FILES})
|
|
||||||
|
|
||||||
endfunction(includefolder)
|
list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/StackWalker.cpp" "${PROJECT_SOURCE_DIR}/LeakFinder.cpp")
|
||||||
|
|
||||||
foreach(folder ${FOLDERS})
|
else ()
|
||||||
includefolder(${folder})
|
|
||||||
endforeach(folder)
|
|
||||||
|
|
||||||
file(GLOB_RECURSE SOURCE
|
function(includefolder PATH)
|
||||||
"*.cpp"
|
FILE(GLOB FOLDER_FILES
|
||||||
"*.h"
|
"${PATH}/*.cpp"
|
||||||
)
|
"${PATH}/*.h"
|
||||||
|
)
|
||||||
|
source_group("${PATH}" FILES ${FOLDER_FILES})
|
||||||
|
endfunction(includefolder)
|
||||||
|
|
||||||
include_directories("${PROJECT_SOURCE_DIR}")
|
foreach(folder ${FOLDERS})
|
||||||
|
includefolder(${folder})
|
||||||
|
endforeach(folder)
|
||||||
|
|
||||||
source_group("" FILES ${SOURCE})
|
file(GLOB_RECURSE SOURCE
|
||||||
|
"*.cpp"
|
||||||
|
"*.h"
|
||||||
|
)
|
||||||
|
|
||||||
#precompiledheaders
|
include_directories("${PROJECT_SOURCE_DIR}")
|
||||||
|
|
||||||
file(GLOB_RECURSE HEADERS
|
source_group("" FILES ${SOURCE})
|
||||||
"*.h"
|
|
||||||
)
|
|
||||||
|
|
||||||
foreach(header ${HEADERS})
|
|
||||||
set(FLAGS "/Yu ${header} /Yc ${header}")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}")
|
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAGS}")
|
|
||||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAGS}")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAGS}")
|
|
||||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${FLAGS}")
|
|
||||||
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_PROFILE} ${FLAGS}")
|
|
||||||
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_PROFILE} ${FLAGS}")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
|
# Precompiled headers (1st part)
|
||||||
|
SET_SOURCE_FILES_PROPERTIES(
|
||||||
|
Globals.cpp PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\""
|
||||||
|
)
|
||||||
|
# CMake cannot "remove" the precompiled header flags, so we use a dummy precompiled header compatible with just this one file:
|
||||||
|
SET_SOURCE_FILES_PROPERTIES(
|
||||||
|
Bindings/Bindings.cpp PROPERTIES COMPILE_FLAGS "/Yc\"string.h\" /Fp\"$(IntDir)/Bindings.pch\""
|
||||||
|
)
|
||||||
|
SET_SOURCE_FILES_PROPERTIES(
|
||||||
|
"StackWalker.cpp LeakFinder.h" PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\""
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/StackWalker.cpp" "${PROJECT_SOURCE_DIR}/LeakFinder.cpp")
|
|
||||||
|
|
||||||
if(UNIX)
|
if (UNIX)
|
||||||
set(EXECUTABLE ../MCServer/MCServer)
|
set(EXECUTABLE ../MCServer/MCServer)
|
||||||
else()
|
else ()
|
||||||
set(EXECUTABLE MCServer)
|
set(EXECUTABLE MCServer)
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
add_executable(${EXECUTABLE} ${SOURCE})
|
add_executable(${EXECUTABLE} ${SOURCE})
|
||||||
|
|
||||||
if(NOT WIN32)
|
|
||||||
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
|
# Precompiled headers (2nd part)
|
||||||
target_link_libraries(${EXECUTABLE} Protocol Generating WorldStorage)
|
if (WIN32)
|
||||||
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities)
|
SET_TARGET_PROPERTIES(
|
||||||
|
${EXECUTABLE} PROPERTIES COMPILE_FLAGS "/Yu\"Globals.h\""
|
||||||
|
OBJECT_DEPENDS "$(IntDir)/$(TargetName.pch)"
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
|
if (NOT WIN32)
|
||||||
|
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
|
||||||
|
target_link_libraries(${EXECUTABLE} Protocol Generating WorldStorage)
|
||||||
|
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities)
|
||||||
|
endif ()
|
||||||
|
if (WIN32)
|
||||||
|
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(${EXECUTABLE} md5 luaexpat iniFile jsoncpp cryptopp zlib lua)
|
target_link_libraries(${EXECUTABLE} md5 luaexpat iniFile jsoncpp cryptopp zlib lua sqlite)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
#include "ChatColor.h"
|
#include "ChatColor.h"
|
||||||
|
@ -29,11 +28,5 @@ const std::string cChatColor::Underlined = cChatColor::Color + "n";
|
||||||
const std::string cChatColor::Italic = cChatColor::Color + "o";
|
const std::string cChatColor::Italic = cChatColor::Color + "o";
|
||||||
const std::string cChatColor::Plain = cChatColor::Color + "r";
|
const std::string cChatColor::Plain = cChatColor::Color + "r";
|
||||||
|
|
||||||
const std::string cChatColor::MakeColor( char a_Color )
|
|
||||||
{
|
|
||||||
return cChatColor::Color + a_Color;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,15 +29,14 @@ public:
|
||||||
static const std::string Yellow;
|
static const std::string Yellow;
|
||||||
static const std::string White;
|
static const std::string White;
|
||||||
|
|
||||||
// Styles ( source: http://wiki.vg/Chat )
|
// Styles ( source: http://wiki.vg/Chat )
|
||||||
static const std::string Random;
|
static const std::string Random;
|
||||||
static const std::string Bold;
|
static const std::string Bold;
|
||||||
static const std::string Strikethrough;
|
static const std::string Strikethrough;
|
||||||
static const std::string Underlined;
|
static const std::string Underlined;
|
||||||
static const std::string Italic;
|
static const std::string Italic;
|
||||||
static const std::string Plain;
|
static const std::string Plain;
|
||||||
|
|
||||||
static const std::string MakeColor( char a_Color );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
|
@ -2744,6 +2744,22 @@ void cChunk::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunk::BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude)
|
||||||
|
{
|
||||||
|
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr )
|
||||||
|
{
|
||||||
|
if (*itr == a_Exclude)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(*itr)->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount);
|
||||||
|
} // for itr - LoadedByClient[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunk::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude)
|
void cChunk::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude)
|
||||||
{
|
{
|
||||||
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr )
|
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr )
|
||||||
|
|
|
@ -277,6 +277,7 @@ public:
|
||||||
void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
|
void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
|
void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
|
||||||
|
void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
|
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8
|
void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8
|
||||||
void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL);
|
void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL);
|
||||||
|
|
|
@ -605,6 +605,25 @@ void cChunkMap::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
int ChunkX, ChunkZ;
|
||||||
|
|
||||||
|
cChunkDef::BlockToChunk((int) a_SrcX, (int) a_SrcZ, ChunkX, ChunkZ);
|
||||||
|
cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ);
|
||||||
|
if (Chunk == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// It's perfectly legal to broadcast packets even to invalid chunks!
|
||||||
|
Chunk->BroadcastParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount, a_Exclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude)
|
void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSLayers);
|
cCSLock Lock(m_CSLayers);
|
||||||
|
|
|
@ -74,6 +74,7 @@ public:
|
||||||
void BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
|
void BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastEntityVelocity(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
void BroadcastEntityVelocity(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
|
void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
|
||||||
|
void BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
|
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8
|
void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8
|
||||||
void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL);
|
void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL);
|
||||||
|
|
|
@ -1872,6 +1872,15 @@ void cClientHandle::SendInventorySlot(char a_WindowID, short a_SlotNum, const cI
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cClientHandle::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
|
||||||
|
{
|
||||||
|
m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cClientHandle::SendPickupSpawn(const cPickup & a_Pickup)
|
void cClientHandle::SendPickupSpawn(const cPickup & a_Pickup)
|
||||||
{
|
{
|
||||||
m_Protocol->SendPickupSpawn(a_Pickup);
|
m_Protocol->SendPickupSpawn(a_Pickup);
|
||||||
|
|
|
@ -113,6 +113,7 @@ public:
|
||||||
void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item);
|
void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item);
|
||||||
void SendPickupSpawn (const cPickup & a_Pickup);
|
void SendPickupSpawn (const cPickup & a_Pickup);
|
||||||
void SendEntityAnimation (const cEntity & a_Entity, char a_Animation);
|
void SendEntityAnimation (const cEntity & a_Entity, char a_Animation);
|
||||||
|
void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount);
|
||||||
void SendPlayerAbilities (void);
|
void SendPlayerAbilities (void);
|
||||||
void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline);
|
void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline);
|
||||||
void SendPlayerMaxSpeed (void); ///< Informs the client of the maximum player speed (1.6.1+)
|
void SendPlayerMaxSpeed (void); ///< Informs the client of the maximum player speed (1.6.1+)
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "../Bindings/PluginManager.h"
|
#include "../Bindings/PluginManager.h"
|
||||||
#include "../Tracer.h"
|
#include "../Tracer.h"
|
||||||
#include "Minecart.h"
|
#include "Minecart.h"
|
||||||
|
#include "Player.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -239,10 +240,14 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R
|
||||||
TDI.Attacker = a_Attacker;
|
TDI.Attacker = a_Attacker;
|
||||||
TDI.RawDamage = a_RawDamage;
|
TDI.RawDamage = a_RawDamage;
|
||||||
TDI.FinalDamage = a_FinalDamage;
|
TDI.FinalDamage = a_FinalDamage;
|
||||||
Vector3d Heading;
|
|
||||||
Heading.x = sin(GetRotation());
|
Vector3d Heading(0, 0, 0);
|
||||||
Heading.y = 0.4; // TODO: adjust the amount of "up" knockback when testing
|
if (a_Attacker != NULL)
|
||||||
Heading.z = cos(GetRotation());
|
{
|
||||||
|
Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 10 : 8);
|
||||||
|
}
|
||||||
|
Heading.y = 2;
|
||||||
|
|
||||||
TDI.Knockback = Heading * a_KnockbackAmount;
|
TDI.Knockback = Heading * a_KnockbackAmount;
|
||||||
DoTakeDamage(TDI);
|
DoTakeDamage(TDI);
|
||||||
}
|
}
|
||||||
|
@ -297,6 +302,16 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
|
||||||
|
{
|
||||||
|
// IsOnGround() only is false if the player is moving downwards
|
||||||
|
if (!((cPlayer *)a_TDI.Attacker)->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain)
|
||||||
|
{
|
||||||
|
a_TDI.FinalDamage += 2;
|
||||||
|
m_World->BroadcastEntityAnimation(*this, 4); // Critical hit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_Health -= (short)a_TDI.FinalDamage;
|
m_Health -= (short)a_TDI.FinalDamage;
|
||||||
|
|
||||||
// TODO: Apply damage to armor
|
// TODO: Apply damage to armor
|
||||||
|
@ -306,6 +321,8 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
m_Health = 0;
|
m_Health = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AddSpeed(a_TDI.Knockback * 2);
|
||||||
|
|
||||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT);
|
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT);
|
||||||
|
|
||||||
if (m_Health <= 0)
|
if (m_Health <= 0)
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
|
|
||||||
|
#include "../BoundingBox.h"
|
||||||
|
#include "../Chunk.h"
|
||||||
#include "Floater.h"
|
#include "Floater.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "../ClientHandle.h"
|
#include "../ClientHandle.h"
|
||||||
|
@ -9,11 +11,103 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID) :
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
cEntity(etFloater, a_X, a_Y, a_Z, 0.98, 0.98),
|
// cFloaterEntityCollisionCallback
|
||||||
|
class cFloaterEntityCollisionCallback :
|
||||||
|
public cEntityCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cFloaterEntityCollisionCallback(cFloater * a_Floater, const Vector3d & a_Pos, const Vector3d & a_NextPos) :
|
||||||
|
m_Floater(a_Floater),
|
||||||
|
m_Pos(a_Pos),
|
||||||
|
m_NextPos(a_NextPos),
|
||||||
|
m_MinCoeff(1),
|
||||||
|
m_HitEntity(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual bool Item(cEntity * a_Entity) override
|
||||||
|
{
|
||||||
|
if (!a_Entity->IsMob()) // Floaters can only pull mobs not other entities.
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
|
||||||
|
|
||||||
|
double LineCoeff;
|
||||||
|
char Face;
|
||||||
|
EntBox.Expand(m_Floater->GetWidth() / 2, m_Floater->GetHeight() / 2, m_Floater->GetWidth() / 2);
|
||||||
|
if (!EntBox.CalcLineIntersection(m_Pos, m_NextPos, LineCoeff, Face))
|
||||||
|
{
|
||||||
|
// No intersection whatsoever
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LineCoeff < m_MinCoeff)
|
||||||
|
{
|
||||||
|
// The entity is closer than anything we've stored so far, replace it as the potential victim
|
||||||
|
m_MinCoeff = LineCoeff;
|
||||||
|
m_HitEntity = a_Entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't break the enumeration, we want all the entities
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the nearest entity that was hit, after the enumeration has been completed
|
||||||
|
cEntity * GetHitEntity(void) const { return m_HitEntity; }
|
||||||
|
|
||||||
|
/// Returns true if the callback has encountered a true hit
|
||||||
|
bool HasHit(void) const { return (m_MinCoeff < 1); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
cFloater * m_Floater;
|
||||||
|
const Vector3d & m_Pos;
|
||||||
|
const Vector3d & m_NextPos;
|
||||||
|
double m_MinCoeff; // The coefficient of the nearest hit on the Pos line
|
||||||
|
|
||||||
|
// Although it's bad(tm) to store entity ptrs from a callback, we can afford it here, because the entire callback
|
||||||
|
// is processed inside the tick thread, so the entities won't be removed in between the calls and the final processing
|
||||||
|
cEntity * m_HitEntity; // The nearest hit entity
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cFloaterCheckEntityExist
|
||||||
|
class cFloaterCheckEntityExist :
|
||||||
|
public cEntityCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cFloaterCheckEntityExist(void) :
|
||||||
|
m_EntityExists(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Item(cEntity * a_Entity) override
|
||||||
|
{
|
||||||
|
m_EntityExists = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DoesExist(void) const { return m_EntityExists; }
|
||||||
|
protected:
|
||||||
|
bool m_EntityExists;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime) :
|
||||||
|
cEntity(etFloater, a_X, a_Y, a_Z, 0.2, 0.2),
|
||||||
m_PickupCountDown(0),
|
m_PickupCountDown(0),
|
||||||
m_PlayerID(a_PlayerID),
|
m_PlayerID(a_PlayerID),
|
||||||
m_CanPickupItem(false)
|
m_CanPickupItem(false),
|
||||||
|
m_CountDownTime(a_CountDownTime),
|
||||||
|
m_AttachedMobID(-1)
|
||||||
{
|
{
|
||||||
SetSpeed(a_Speed);
|
SetSpeed(a_Speed);
|
||||||
}
|
}
|
||||||
|
@ -36,21 +130,49 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
|
||||||
HandlePhysics(a_Dt, a_Chunk);
|
HandlePhysics(a_Dt, a_Chunk);
|
||||||
if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())) && m_World->GetBlockMeta((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()) == 0)
|
if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())) && m_World->GetBlockMeta((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()) == 0)
|
||||||
{
|
{
|
||||||
if ((!m_CanPickupItem) && (m_World->GetTickRandomNumber(100) == 0))
|
if ((!m_CanPickupItem) && (m_AttachedMobID == -1)) // Check if you can't already pickup a fish and if the floater isn't attached to a mob.
|
||||||
{
|
{
|
||||||
SetPosY(GetPosY() - 1);
|
if (m_CountDownTime <= 0)
|
||||||
m_CanPickupItem = true;
|
{
|
||||||
m_PickupCountDown = 20;
|
m_World->BroadcastSoundEffect("random.splash", (int) floor(GetPosX() * 8), (int) floor(GetPosY() * 8), (int) floor(GetPosZ() * 8), 1, 1);
|
||||||
LOGD("Floater %i can be picked up", GetUniqueID());
|
SetPosY(GetPosY() - 1);
|
||||||
}
|
m_CanPickupItem = true;
|
||||||
else
|
m_PickupCountDown = 20;
|
||||||
{
|
m_CountDownTime = 100 + m_World->GetTickRandomNumber(800);
|
||||||
SetSpeedY(0.7);
|
LOGD("Floater %i can be picked up", GetUniqueID());
|
||||||
|
}
|
||||||
|
else if (m_CountDownTime == 20) // Calculate the position where the particles should spawn and start producing them.
|
||||||
|
{
|
||||||
|
LOGD("Started producing particles for floater %i", GetUniqueID());
|
||||||
|
m_ParticlePos.Set(GetPosX() + (-4 + m_World->GetTickRandomNumber(8)), GetPosY(), GetPosZ() + (-4 + m_World->GetTickRandomNumber(8)));
|
||||||
|
m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15);
|
||||||
|
}
|
||||||
|
else if (m_CountDownTime < 20)
|
||||||
|
{
|
||||||
|
m_ParticlePos = (m_ParticlePos + (GetPosition() - m_ParticlePos) / 6);
|
||||||
|
m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_CountDownTime--;
|
||||||
|
if (m_World->GetHeight((int) GetPosX(), (int) GetPosZ()) == (int) GetPosY())
|
||||||
|
{
|
||||||
|
if (m_World->IsWeatherWet() && m_World->GetTickRandomNumber(3) == 0) // 25% chance of an extra countdown when being rained on.
|
||||||
|
{
|
||||||
|
m_CountDownTime--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // if the floater is underground it has a 50% chance of not decreasing the countdown.
|
||||||
|
{
|
||||||
|
if (m_World->GetTickRandomNumber(1) == 0)
|
||||||
|
{
|
||||||
|
m_CountDownTime++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
SetSpeedY(0.7);
|
||||||
}
|
}
|
||||||
SetSpeedX(GetSpeedX() * 0.95);
|
|
||||||
SetSpeedZ(GetSpeedZ() * 0.95);
|
if (CanPickup()) // Make sure the floater "loses its fish"
|
||||||
if (CanPickup())
|
|
||||||
{
|
{
|
||||||
m_PickupCountDown--;
|
m_PickupCountDown--;
|
||||||
if (m_PickupCountDown == 0)
|
if (m_PickupCountDown == 0)
|
||||||
|
@ -59,9 +181,38 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
|
||||||
LOGD("The fish is gone. Floater %i can not pick an item up.", GetUniqueID());
|
LOGD("The fish is gone. Floater %i can not pick an item up.", GetUniqueID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((GetSpeed().Length() > 4) && (m_AttachedMobID == -1))
|
||||||
|
{
|
||||||
|
cFloaterEntityCollisionCallback Callback(this, GetPosition(), GetPosition() + GetSpeed() / 20);
|
||||||
|
|
||||||
|
a_Chunk.ForEachEntity(Callback);
|
||||||
|
if (Callback.HasHit())
|
||||||
|
{
|
||||||
|
AttachTo(Callback.GetHitEntity());
|
||||||
|
Callback.GetHitEntity()->TakeDamage(*this); // TODO: the player attacked the mob not the floater.
|
||||||
|
m_AttachedMobID = Callback.GetHitEntity()->GetUniqueID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cFloaterCheckEntityExist EntityCallback;
|
||||||
|
m_World->DoWithEntityByID(m_PlayerID, EntityCallback);
|
||||||
|
if (!EntityCallback.DoesExist()) // The owner doesn't exist anymore. Destroy the floater entity.
|
||||||
|
{
|
||||||
|
Destroy(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_AttachedMobID != -1)
|
||||||
|
{
|
||||||
|
m_World->DoWithEntityByID(m_AttachedMobID, EntityCallback); // The mob the floater was attached to doesn't exist anymore.
|
||||||
|
if (!EntityCallback.DoesExist())
|
||||||
|
{
|
||||||
|
m_AttachedMobID = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSpeedX(GetSpeedX() * 0.95);
|
||||||
|
SetSpeedZ(GetSpeedZ() * 0.95);
|
||||||
|
|
||||||
BroadcastMovementUpdate();
|
BroadcastMovementUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,16 +14,27 @@ class cFloater :
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID);
|
cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime);
|
||||||
|
|
||||||
virtual void SpawnOn(cClientHandle & a_Client) override;
|
virtual void SpawnOn(cClientHandle & a_Client) override;
|
||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
|
||||||
bool CanPickup(void) const { return m_CanPickupItem; }
|
bool CanPickup(void) const { return m_CanPickupItem; }
|
||||||
|
int GetOwnerID(void) const { return m_PlayerID; }
|
||||||
|
int GetAttachedMobID(void) const { return m_AttachedMobID; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Vector3d m_Speed;
|
// Position
|
||||||
int m_PickupCountDown;
|
Vector3d m_ParticlePos;
|
||||||
int m_PlayerID;
|
|
||||||
|
// Bool needed to check if you can get a fish.
|
||||||
bool m_CanPickupItem;
|
bool m_CanPickupItem;
|
||||||
|
|
||||||
|
// Countdown times
|
||||||
|
int m_PickupCountDown;
|
||||||
|
int m_CountDownTime;
|
||||||
|
|
||||||
|
// Entity IDs
|
||||||
|
int m_PlayerID;
|
||||||
|
int m_AttachedMobID;
|
||||||
} ;
|
} ;
|
|
@ -240,6 +240,11 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
|
||||||
HandleFood();
|
HandleFood();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_IsFishing)
|
||||||
|
{
|
||||||
|
HandleFloater();
|
||||||
|
}
|
||||||
|
|
||||||
// Send Player List (Once per m_LastPlayerListTime/1000 ms)
|
// Send Player List (Once per m_LastPlayerListTime/1000 ms)
|
||||||
cTimer t1;
|
cTimer t1;
|
||||||
if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime())
|
if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime())
|
||||||
|
@ -247,6 +252,11 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
|
||||||
m_World->SendPlayerList(this);
|
m_World->SendPlayerList(this);
|
||||||
m_LastPlayerListTime = t1.GetNowTime();
|
m_LastPlayerListTime = t1.GetNowTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsFlying())
|
||||||
|
{
|
||||||
|
m_LastGroundHeight = (float)GetPosY();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -447,10 +457,16 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
|
||||||
if (m_LastJumpHeight > m_LastGroundHeight) Damage++;
|
if (m_LastJumpHeight > m_LastGroundHeight) Damage++;
|
||||||
m_LastJumpHeight = (float)GetPosY();
|
m_LastJumpHeight = (float)GetPosY();
|
||||||
|
|
||||||
if ((Damage > 0) && (!IsGameModeCreative()))
|
if (Damage > 0)
|
||||||
{
|
{
|
||||||
TakeDamage(dtFalling, NULL, Damage, Damage, 0);
|
if (!IsGameModeCreative())
|
||||||
}
|
{
|
||||||
|
TakeDamage(dtFalling, NULL, Damage, Damage, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mojang uses floor() to get X and Z positions, instead of just casting it to an (int)
|
||||||
|
GetWorld()->BroadcastSoundParticleEffect(2006, (int)floor(GetPosX()), (int)GetPosY() - 1, (int)floor(GetPosZ()), Damage /* Used as particle effect speed modifier */);
|
||||||
|
}
|
||||||
|
|
||||||
m_LastGroundHeight = (float)GetPosY();
|
m_LastGroundHeight = (float)GetPosY();
|
||||||
}
|
}
|
||||||
|
@ -804,6 +820,22 @@ void cPlayer::KilledBy(cEntity * a_Killer)
|
||||||
m_Inventory.Clear();
|
m_Inventory.Clear();
|
||||||
m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
|
m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
|
||||||
SaveToDisk(); // Save it, yeah the world is a tough place !
|
SaveToDisk(); // Save it, yeah the world is a tough place !
|
||||||
|
|
||||||
|
if (a_Killer == NULL)
|
||||||
|
{
|
||||||
|
GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by environmental damage", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str()));
|
||||||
|
}
|
||||||
|
else if (a_Killer->IsPlayer())
|
||||||
|
{
|
||||||
|
GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), ((cPlayer *)a_Killer)->GetName().c_str()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AString KillerClass = a_Killer->GetClass();
|
||||||
|
KillerClass.erase(KillerClass.begin()); // Erase the 'c' of the class (e.g. "cWitch" -> "Witch")
|
||||||
|
|
||||||
|
GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by a %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), KillerClass.c_str()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -974,6 +1006,12 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
|
||||||
|
|
||||||
m_GameMode = a_GameMode;
|
m_GameMode = a_GameMode;
|
||||||
m_ClientHandle->SendGameMode(a_GameMode);
|
m_ClientHandle->SendGameMode(a_GameMode);
|
||||||
|
|
||||||
|
if (!IsGameModeCreative())
|
||||||
|
{
|
||||||
|
SetFlying(false);
|
||||||
|
SetCanFly(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1289,7 +1327,7 @@ AString cPlayer::GetColor(void) const
|
||||||
{
|
{
|
||||||
if ( m_Color != '-' )
|
if ( m_Color != '-' )
|
||||||
{
|
{
|
||||||
return cChatColor::MakeColor( m_Color );
|
return cChatColor::Color + m_Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( m_Groups.size() < 1 )
|
if ( m_Groups.size() < 1 )
|
||||||
|
@ -1781,6 +1819,30 @@ void cPlayer::HandleFood(void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cPlayer::HandleFloater()
|
||||||
|
{
|
||||||
|
if (GetEquippedItem().m_ItemType == E_ITEM_FISHING_ROD)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
class cFloaterCallback :
|
||||||
|
public cEntityCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool Item(cEntity * a_Entity) override
|
||||||
|
{
|
||||||
|
a_Entity->Destroy(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} Callback;
|
||||||
|
m_World->DoWithEntityByID(m_FloaterID, Callback);
|
||||||
|
SetIsFishing(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPlayer::ApplyFoodExhaustionFromMovement()
|
void cPlayer::ApplyFoodExhaustionFromMovement()
|
||||||
{
|
{
|
||||||
if (IsGameModeCreative())
|
if (IsGameModeCreative())
|
||||||
|
|
|
@ -466,6 +466,9 @@ protected:
|
||||||
|
|
||||||
/// Called in each tick to handle food-related processing
|
/// Called in each tick to handle food-related processing
|
||||||
void HandleFood(void);
|
void HandleFood(void);
|
||||||
|
|
||||||
|
/// Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item.
|
||||||
|
void HandleFloater(void);
|
||||||
|
|
||||||
/// Called in each tick to handle air-related processing i.e. drowning
|
/// Called in each tick to handle air-related processing i.e. drowning
|
||||||
void HandleAir();
|
void HandleAir();
|
||||||
|
|
|
@ -101,7 +101,21 @@ static cDistortedHeightmap::sBlockInfo tbMycelium[] =
|
||||||
{E_BLOCK_DIRT, 0},
|
{E_BLOCK_DIRT, 0},
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
static cDistortedHeightmap::sBlockInfo tbGravel[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_GRAVEL, 0},
|
||||||
|
{E_BLOCK_GRAVEL, 0},
|
||||||
|
{E_BLOCK_GRAVEL, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static cDistortedHeightmap::sBlockInfo tbStone[] =
|
||||||
|
{
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
{E_BLOCK_STONE, 0},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -146,6 +160,8 @@ static cPattern patDirt (tbDirt, ARRAYCOUNT(tbDirt));
|
||||||
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol));
|
||||||
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess));
|
||||||
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium));
|
||||||
|
static cPattern patGravel (tbGravel, ARRAYCOUNT(tbGravel));
|
||||||
|
static cPattern patStone (tbStone, ARRAYCOUNT(tbStone));
|
||||||
|
|
||||||
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand));
|
||||||
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay));
|
||||||
|
@ -648,7 +664,6 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in
|
||||||
{
|
{
|
||||||
case biOcean:
|
case biOcean:
|
||||||
case biPlains:
|
case biPlains:
|
||||||
case biExtremeHills:
|
|
||||||
case biForest:
|
case biForest:
|
||||||
case biTaiga:
|
case biTaiga:
|
||||||
case biSwampland:
|
case biSwampland:
|
||||||
|
@ -671,11 +686,9 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in
|
||||||
case biRoofedForest:
|
case biRoofedForest:
|
||||||
case biColdTaiga:
|
case biColdTaiga:
|
||||||
case biColdTaigaHills:
|
case biColdTaigaHills:
|
||||||
case biExtremeHillsPlus:
|
|
||||||
case biSavanna:
|
case biSavanna:
|
||||||
case biSavannaPlateau:
|
case biSavannaPlateau:
|
||||||
case biSunflowerPlains:
|
case biSunflowerPlains:
|
||||||
case biExtremeHillsM:
|
|
||||||
case biFlowerForest:
|
case biFlowerForest:
|
||||||
case biTaigaM:
|
case biTaigaM:
|
||||||
case biSwamplandM:
|
case biSwamplandM:
|
||||||
|
@ -686,7 +699,6 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in
|
||||||
case biBirchForestHillsM:
|
case biBirchForestHillsM:
|
||||||
case biRoofedForestM:
|
case biRoofedForestM:
|
||||||
case biColdTaigaM:
|
case biColdTaigaM:
|
||||||
case biExtremeHillsPlusM:
|
|
||||||
case biSavannaM:
|
case biSavannaM:
|
||||||
case biSavannaPlateauM:
|
case biSavannaPlateauM:
|
||||||
{
|
{
|
||||||
|
@ -737,6 +749,30 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in
|
||||||
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ);
|
FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case biExtremeHillsPlus:
|
||||||
|
case biExtremeHills:
|
||||||
|
{
|
||||||
|
// Select the pattern to use - stone or grass:
|
||||||
|
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||||
|
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||||
|
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||||
|
const sBlockInfo * Pattern = (Val < -0.1) ? patStone.Get() : patGrass.Get();
|
||||||
|
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biExtremeHillsPlusM:
|
||||||
|
case biExtremeHillsM:
|
||||||
|
{
|
||||||
|
// Select the pattern to use - gravel, stone or grass:
|
||||||
|
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX;
|
||||||
|
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ;
|
||||||
|
NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY);
|
||||||
|
const sBlockInfo * Pattern = (Val < -0.9) ? patStone.Get() : ((Val > 0) ? patGravel.Get() : patGrass.Get());
|
||||||
|
FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern);
|
||||||
|
return;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ASSERT(!"Unhandled biome");
|
ASSERT(!"Unhandled biome");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -216,7 +216,14 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
|
||||||
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case biBirchForestM:
|
||||||
|
case biBirchForestHillsM:
|
||||||
|
{
|
||||||
|
GetTallBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case biRoofedForest:
|
case biRoofedForest:
|
||||||
case biColdTaiga:
|
case biColdTaiga:
|
||||||
case biColdTaigaHills:
|
case biColdTaigaHills:
|
||||||
|
@ -237,8 +244,6 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
|
||||||
case biIcePlainsSpikes:
|
case biIcePlainsSpikes:
|
||||||
case biJungleM:
|
case biJungleM:
|
||||||
case biJungleEdgeM:
|
case biJungleEdgeM:
|
||||||
case biBirchForestM:
|
|
||||||
case biBirchForestHillsM:
|
|
||||||
case biRoofedForestM:
|
case biRoofedForestM:
|
||||||
case biColdTaigaM:
|
case biColdTaigaM:
|
||||||
case biMegaSpruceTaiga:
|
case biMegaSpruceTaiga:
|
||||||
|
@ -377,6 +382,44 @@ void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Nois
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetTallBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks)
|
||||||
|
{
|
||||||
|
int Height = 9 + (a_Noise.IntNoise3DInt(a_BlockX + 64 * a_Seq, a_BlockY, a_BlockZ) % 3);
|
||||||
|
|
||||||
|
// Prealloc, so that we don't realloc too often later:
|
||||||
|
a_LogBlocks.reserve(Height);
|
||||||
|
a_OtherBlocks.reserve(80);
|
||||||
|
|
||||||
|
// The entire trunk, out of logs:
|
||||||
|
for (int i = Height - 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_LOG, E_META_LOG_BIRCH));
|
||||||
|
}
|
||||||
|
int h = a_BlockY + Height;
|
||||||
|
|
||||||
|
// Top layer - just the Plus:
|
||||||
|
PushCoordBlocks(a_BlockX, h, a_BlockZ, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH);
|
||||||
|
a_OtherBlocks.push_back(sSetBlock(a_BlockX, h, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH)); // There's no log at this layer
|
||||||
|
h--;
|
||||||
|
|
||||||
|
// Second layer - log, Plus and maybe Corners:
|
||||||
|
PushCoordBlocks (a_BlockX, h, a_BlockZ, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH);
|
||||||
|
PushCornerBlocks(a_BlockX, h, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 1, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH);
|
||||||
|
h--;
|
||||||
|
|
||||||
|
// Third and fourth layers - BigO2 and maybe 2*Corners:
|
||||||
|
for (int Row = 0; Row < 2; Row++)
|
||||||
|
{
|
||||||
|
PushCoordBlocks (a_BlockX, h, a_BlockZ, a_OtherBlocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH);
|
||||||
|
PushCornerBlocks(a_BlockX, h, a_BlockZ, a_Seq, a_Noise, 0x3fffffff + Row * 0x10000000, a_OtherBlocks, 2, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH);
|
||||||
|
h--;
|
||||||
|
} // for Row - 2*
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void GetConiferTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks)
|
void GetConiferTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks)
|
||||||
{
|
{
|
||||||
// Half chance for a spruce, half for a pine:
|
// Half chance for a spruce, half for a pine:
|
||||||
|
|
|
@ -63,6 +63,9 @@ void GetLargeAppleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a
|
||||||
/// Generates an image of a random birch tree
|
/// Generates an image of a random birch tree
|
||||||
void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks);
|
void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks);
|
||||||
|
|
||||||
|
/// Generates an image of a random large birch tree
|
||||||
|
void GetTallBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks,sSetBlockVector & a_OtherBlocks);
|
||||||
|
|
||||||
/// Generates an image of a random conifer tree
|
/// Generates an image of a random conifer tree
|
||||||
void GetConiferTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks);
|
void GetConiferTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks);
|
||||||
|
|
||||||
|
|
|
@ -79,11 +79,11 @@ cGroupManager::cGroupManager()
|
||||||
Group->SetName( KeyName );
|
Group->SetName( KeyName );
|
||||||
char Color = IniFile.GetValue( KeyName, "Color", "-" )[0];
|
char Color = IniFile.GetValue( KeyName, "Color", "-" )[0];
|
||||||
if( Color != '-' )
|
if( Color != '-' )
|
||||||
Group->SetColor( cChatColor::MakeColor(Color) );
|
Group->SetColor( cChatColor::Color + Color );
|
||||||
else
|
else
|
||||||
Group->SetColor( cChatColor::White );
|
Group->SetColor( cChatColor::White );
|
||||||
|
|
||||||
std::string Commands = IniFile.GetValue( KeyName, "Commands", "" );
|
AString Commands = IniFile.GetValue( KeyName, "Commands", "" );
|
||||||
if( Commands.size() > 0 )
|
if( Commands.size() > 0 )
|
||||||
{
|
{
|
||||||
AStringVector Split = StringSplit( Commands, "," );
|
AStringVector Split = StringSplit( Commands, "," );
|
||||||
|
@ -93,7 +93,7 @@ cGroupManager::cGroupManager()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Permissions = IniFile.GetValue( KeyName, "Permissions", "" );
|
AString Permissions = IniFile.GetValue( KeyName, "Permissions", "" );
|
||||||
if( Permissions.size() > 0 )
|
if( Permissions.size() > 0 )
|
||||||
{
|
{
|
||||||
AStringVector Split = StringSplit( Permissions, "," );
|
AStringVector Split = StringSplit( Permissions, "," );
|
||||||
|
|
|
@ -580,11 +580,11 @@ bool cItemGrid::DamageItem(int a_X, int a_Y, short a_Amount)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, int a_CountLootProbabs, int a_NumSlots, int a_Seed)
|
void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, size_t a_CountLootProbabs, int a_NumSlots, int a_Seed)
|
||||||
{
|
{
|
||||||
// Calculate the total weight:
|
// Calculate the total weight:
|
||||||
int TotalProbab = 1;
|
int TotalProbab = 1;
|
||||||
for (int i = 0; i < a_CountLootProbabs; i++)
|
for (size_t i = 0; i < a_CountLootProbabs; i++)
|
||||||
{
|
{
|
||||||
TotalProbab += a_LootProbabs[i].m_Weight;
|
TotalProbab += a_LootProbabs[i].m_Weight;
|
||||||
}
|
}
|
||||||
|
@ -597,7 +597,7 @@ void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, i
|
||||||
int LootRnd = Rnd % TotalProbab;
|
int LootRnd = Rnd % TotalProbab;
|
||||||
Rnd >>= 8;
|
Rnd >>= 8;
|
||||||
cItem CurrentLoot = cItem(E_ITEM_BOOK, 1, 0); // TODO: enchantment
|
cItem CurrentLoot = cItem(E_ITEM_BOOK, 1, 0); // TODO: enchantment
|
||||||
for (int j = 0; j < a_CountLootProbabs; j++)
|
for (size_t j = 0; j < a_CountLootProbabs; j++)
|
||||||
{
|
{
|
||||||
LootRnd -= a_LootProbabs[i].m_Weight;
|
LootRnd -= a_LootProbabs[i].m_Weight;
|
||||||
if (LootRnd < 0)
|
if (LootRnd < 0)
|
||||||
|
|
|
@ -157,7 +157,7 @@ public:
|
||||||
A total of a_NumSlots are taken by the loot.
|
A total of a_NumSlots are taken by the loot.
|
||||||
Cannot export to Lua due to raw array a_LootProbabs. TODO: Make this exportable / export through ManualBindings.cpp with a Lua table as LootProbabs
|
Cannot export to Lua due to raw array a_LootProbabs. TODO: Make this exportable / export through ManualBindings.cpp with a Lua table as LootProbabs
|
||||||
*/
|
*/
|
||||||
void GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, int a_CountLootProbabs, int a_NumSlots, int a_Seed);
|
void GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, size_t a_CountLootProbabs, int a_NumSlots, int a_Seed);
|
||||||
|
|
||||||
/// Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback!
|
/// Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback!
|
||||||
void AddListener(cListener & a_Listener);
|
void AddListener(cListener & a_Listener);
|
||||||
|
|
|
@ -15,6 +15,61 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cFloaterCallback
|
||||||
|
class cFloaterCallback :
|
||||||
|
public cEntityCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cFloaterCallback(void) :
|
||||||
|
m_CanPickup(false),
|
||||||
|
m_AttachedMobID(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Item(cEntity * a_Entity) override
|
||||||
|
{
|
||||||
|
m_CanPickup = ((cFloater *)a_Entity)->CanPickup();
|
||||||
|
m_Pos = Vector3d(a_Entity->GetPosX(), a_Entity->GetPosY(), a_Entity->GetPosZ());
|
||||||
|
m_AttachedMobID = ((cFloater *)a_Entity)->GetAttachedMobID();
|
||||||
|
a_Entity->Destroy(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanPickup(void) const { return m_CanPickup; }
|
||||||
|
bool IsAttached(void) const { return (m_AttachedMobID != -1); }
|
||||||
|
int GetAttachedMobID(void) const { return m_AttachedMobID; }
|
||||||
|
Vector3d GetPos(void) const { return m_Pos; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_CanPickup;
|
||||||
|
int m_AttachedMobID;
|
||||||
|
Vector3d m_Pos;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cSweepEntityCallback
|
||||||
|
class cSweepEntityCallback :
|
||||||
|
public cEntityCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cSweepEntityCallback(Vector3d a_PlayerPos) :
|
||||||
|
m_PlayerPos(a_PlayerPos)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Item(cEntity * a_Entity) override
|
||||||
|
{
|
||||||
|
Vector3d Speed = m_PlayerPos - a_Entity->GetPosition();
|
||||||
|
a_Entity->AddSpeed(Speed);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector3d m_PlayerPos;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemFishingRodHandler :
|
class cItemFishingRodHandler :
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
|
@ -36,45 +91,134 @@ public:
|
||||||
|
|
||||||
if (a_Player->IsFishing())
|
if (a_Player->IsFishing())
|
||||||
{
|
{
|
||||||
class cFloaterCallback :
|
cFloaterCallback FloaterInfo;
|
||||||
public cEntityCallback
|
a_World->DoWithEntityByID(a_Player->GetFloaterID(), FloaterInfo);
|
||||||
{
|
|
||||||
public:
|
|
||||||
cFloaterCallback(void) :
|
|
||||||
m_CanPickup(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CanPickup(void) const { return m_CanPickup; }
|
|
||||||
Vector3d GetPos(void) const { return m_Pos; }
|
|
||||||
|
|
||||||
virtual bool Item(cEntity * a_Entity) override
|
|
||||||
{
|
|
||||||
m_CanPickup = ((cFloater *)a_Entity)->CanPickup();
|
|
||||||
m_Pos = Vector3d(a_Entity->GetPosX(), a_Entity->GetPosY(), a_Entity->GetPosZ());
|
|
||||||
a_Entity->Destroy(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
bool m_CanPickup;
|
|
||||||
Vector3d m_Pos;
|
|
||||||
} Callbacks;
|
|
||||||
a_World->DoWithEntityByID(a_Player->GetFloaterID(), Callbacks);
|
|
||||||
a_Player->SetIsFishing(false);
|
a_Player->SetIsFishing(false);
|
||||||
|
|
||||||
if (Callbacks.CanPickup())
|
if (FloaterInfo.IsAttached())
|
||||||
|
{
|
||||||
|
cSweepEntityCallback SweepEntity(a_Player->GetPosition());
|
||||||
|
a_World->DoWithEntityByID(FloaterInfo.GetAttachedMobID(), SweepEntity);
|
||||||
|
}
|
||||||
|
else if (FloaterInfo.CanPickup())
|
||||||
{
|
{
|
||||||
cItems Drops;
|
cItems Drops;
|
||||||
Drops.Add(cItem(E_ITEM_RAW_FISH));
|
int ItemCategory = a_World->GetTickRandomNumber(99);
|
||||||
Vector3d FloaterPos(Callbacks.GetPos());
|
if (ItemCategory <= 4) // Treasures 5%
|
||||||
Vector3d FlyDirection(a_Player->GetPosition() - FloaterPos);
|
{
|
||||||
a_World->SpawnItemPickups(Drops, FloaterPos.x, FloaterPos.y, FloaterPos.z, FlyDirection.x, FlyDirection.Length() / (FlyDirection.y * 2), FlyDirection.z);
|
int Treasure = a_World->GetTickRandomNumber(5);
|
||||||
// TODO: More types of pickups.
|
switch (Treasure)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_BOW)); // TODO: Enchantments
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_BOOK)); // TODO: Enchanted book
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, a_World->GetTickRandomNumber(50))); // Fishing rod with durability. TODO: Enchantments on it
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_NAME_TAG));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_SADDLE));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 5:
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_BLOCK_LILY_PAD));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ItemCategory <= 14) // Junk 10%
|
||||||
|
{
|
||||||
|
int Junk = a_World->GetTickRandomNumber(70);
|
||||||
|
if (Junk <= 1)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_DYE, 10, 0));
|
||||||
|
}
|
||||||
|
else if (Junk <= 4)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_BOW, 1, a_World->GetTickRandomNumber(64)));
|
||||||
|
}
|
||||||
|
else if (Junk <= 9)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_STICK));
|
||||||
|
}
|
||||||
|
else if (Junk <= 14)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_STRING));
|
||||||
|
}
|
||||||
|
else if (Junk <= 22)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_BOWL));
|
||||||
|
}
|
||||||
|
else if (Junk <= 30)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_LEATHER));
|
||||||
|
}
|
||||||
|
else if (Junk <= 38)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_LEATHER_BOOTS));
|
||||||
|
}
|
||||||
|
else if (Junk <= 46)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_ROTTEN_FLESH));
|
||||||
|
}
|
||||||
|
else if (Junk <= 54)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_POTIONS));
|
||||||
|
}
|
||||||
|
else if (Junk <= 62)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_BONE));
|
||||||
|
}
|
||||||
|
else if (Junk <= 70)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_BLOCK_TRIPWIRE_HOOK));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Fish
|
||||||
|
{
|
||||||
|
int FishType = a_World->GetTickRandomNumber(99);
|
||||||
|
if (FishType <= 1) // Clownfish has a 2% chance of spawning
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH));
|
||||||
|
}
|
||||||
|
else if (FishType <= 12) // Pufferfish has a 13% chance of spawning
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH));
|
||||||
|
}
|
||||||
|
else if (FishType <= 24)
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_SALMON));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_FISH));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Vector3d FloaterPos = FloaterInfo.GetPos();
|
||||||
|
Vector3d FlyDirection = a_Player->GetEyePosition() - FloaterPos;
|
||||||
|
a_World->SpawnItemPickups(Drops, FloaterPos.x, FloaterPos.y, FloaterPos.z, FlyDirection.x, FlyDirection.y + 1, FlyDirection.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID());
|
cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), 100 + a_World->GetTickRandomNumber(800) - (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100));
|
||||||
Floater->Initialize(a_World);
|
Floater->Initialize(a_World);
|
||||||
a_Player->SetIsFishing(true, Floater->GetUniqueID());
|
a_Player->SetIsFishing(true, Floater->GetUniqueID());
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,15 +95,11 @@
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
#include <windows.h>
|
#include "Globals.h"
|
||||||
#include <objidl.h> // Needed if compiled with "WIN32_LEAN_AND_MEAN"
|
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
#include <objidl.h> // Needed if compiled with "WIN32_LEAN_AND_MEAN"
|
||||||
#include <crtdbg.h>
|
#include <crtdbg.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
#include "LeakFinder.h"
|
#include "LeakFinder.h"
|
||||||
|
|
||||||
|
@ -463,11 +459,11 @@ public:
|
||||||
pHashEntry->nDataSize = nDataSize;
|
pHashEntry->nDataSize = nDataSize;
|
||||||
pHashEntry->Next = NULL;
|
pHashEntry->Next = NULL;
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
pHashEntry->pCallstackOffset = (LPVOID) min(context.Ebp, context.Esp);
|
pHashEntry->pCallstackOffset = (LPVOID) std::min(context.Ebp, context.Esp);
|
||||||
#elif _M_X64
|
#elif _M_X64
|
||||||
pHashEntry->pCallstackOffset = (LPVOID) min(context.Rdi, context.Rsp);
|
pHashEntry->pCallstackOffset = (LPVOID) std::min(context.Rdi, context.Rsp);
|
||||||
#elif _M_IA64
|
#elif _M_IA64
|
||||||
pHashEntry->pCallstackOffset = (LPVOID) min(context.IntSp, context.RsBSP);
|
pHashEntry->pCallstackOffset = (LPVOID) std::min(context.IntSp, context.RsBSP);
|
||||||
#else
|
#else
|
||||||
#error "Platform not supported!"
|
#error "Platform not supported!"
|
||||||
#endif
|
#endif
|
||||||
|
@ -490,7 +486,7 @@ public:
|
||||||
if (pHashEntry->nMaxStackSize > 0)
|
if (pHashEntry->nMaxStackSize > 0)
|
||||||
{
|
{
|
||||||
SIZE_T len = ((SIZE_T) pHashEntry->pStackBaseAddr + pHashEntry->nMaxStackSize) - (SIZE_T)pHashEntry->pCallstackOffset;
|
SIZE_T len = ((SIZE_T) pHashEntry->pStackBaseAddr + pHashEntry->nMaxStackSize) - (SIZE_T)pHashEntry->pCallstackOffset;
|
||||||
bytesToRead = min(len, MAX_CALLSTACK_LEN_BUF);
|
bytesToRead = std::min(len, (SIZE_T)MAX_CALLSTACK_LEN_BUF);
|
||||||
}
|
}
|
||||||
// Now read the callstack:
|
// Now read the callstack:
|
||||||
if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) pHashEntry->pCallstackOffset, &(pHashEntry->pcCallstackAddr), bytesToRead, &(pHashEntry->nCallstackLen)) == 0)
|
if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) pHashEntry->pCallstackOffset, &(pHashEntry->pcCallstackAddr), bytesToRead, &(pHashEntry->nCallstackLen)) == 0)
|
||||||
|
|
|
@ -40,8 +40,10 @@ static const struct
|
||||||
{cMonster::mtCow, "cow"},
|
{cMonster::mtCow, "cow"},
|
||||||
{cMonster::mtCreeper, "creeper"},
|
{cMonster::mtCreeper, "creeper"},
|
||||||
{cMonster::mtEnderman, "enderman"},
|
{cMonster::mtEnderman, "enderman"},
|
||||||
|
{cMonster::mtEnderDragon, "enderdragon"},
|
||||||
{cMonster::mtGhast, "ghast"},
|
{cMonster::mtGhast, "ghast"},
|
||||||
{cMonster::mtHorse, "horse"},
|
{cMonster::mtHorse, "horse"},
|
||||||
|
{cMonster::mtIronGolem, "irongolem"},
|
||||||
{cMonster::mtMagmaCube, "magmacube"},
|
{cMonster::mtMagmaCube, "magmacube"},
|
||||||
{cMonster::mtMooshroom, "mooshroom"},
|
{cMonster::mtMooshroom, "mooshroom"},
|
||||||
{cMonster::mtOcelot, "ocelot"},
|
{cMonster::mtOcelot, "ocelot"},
|
||||||
|
@ -49,11 +51,13 @@ static const struct
|
||||||
{cMonster::mtSheep, "sheep"},
|
{cMonster::mtSheep, "sheep"},
|
||||||
{cMonster::mtSilverfish, "silverfish"},
|
{cMonster::mtSilverfish, "silverfish"},
|
||||||
{cMonster::mtSkeleton, "skeleton"},
|
{cMonster::mtSkeleton, "skeleton"},
|
||||||
|
{cMonster::mtSnowGolem, "snowgolem"},
|
||||||
{cMonster::mtSlime, "slime"},
|
{cMonster::mtSlime, "slime"},
|
||||||
{cMonster::mtSpider, "spider"},
|
{cMonster::mtSpider, "spider"},
|
||||||
{cMonster::mtSquid, "squid"},
|
{cMonster::mtSquid, "squid"},
|
||||||
{cMonster::mtVillager, "villager"},
|
{cMonster::mtVillager, "villager"},
|
||||||
{cMonster::mtWitch, "witch"},
|
{cMonster::mtWitch, "witch"},
|
||||||
|
{cMonster::mtWither, "wither"},
|
||||||
{cMonster::mtWolf, "wolf"},
|
{cMonster::mtWolf, "wolf"},
|
||||||
{cMonster::mtZombie, "zombie"},
|
{cMonster::mtZombie, "zombie"},
|
||||||
{cMonster::mtZombiePigman, "zombiepigman"},
|
{cMonster::mtZombiePigman, "zombiepigman"},
|
||||||
|
@ -642,9 +646,10 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
|
||||||
case mtEnderman: return mfHostile;
|
case mtEnderman: return mfHostile;
|
||||||
case mtGhast: return mfHostile;
|
case mtGhast: return mfHostile;
|
||||||
case mtHorse: return mfPassive;
|
case mtHorse: return mfPassive;
|
||||||
|
case mtIronGolem: return mfPassive;
|
||||||
case mtMagmaCube: return mfHostile;
|
case mtMagmaCube: return mfHostile;
|
||||||
case mtMooshroom: return mfHostile;
|
case mtMooshroom: return mfHostile;
|
||||||
case mtOcelot: return mfHostile;
|
case mtOcelot: return mfPassive;
|
||||||
case mtPig: return mfPassive;
|
case mtPig: return mfPassive;
|
||||||
case mtSheep: return mfPassive;
|
case mtSheep: return mfPassive;
|
||||||
case mtSilverfish: return mfHostile;
|
case mtSilverfish: return mfHostile;
|
||||||
|
@ -739,16 +744,20 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
|
||||||
case mtChicken: toReturn = new cChicken(); break;
|
case mtChicken: toReturn = new cChicken(); break;
|
||||||
case mtCow: toReturn = new cCow(); break;
|
case mtCow: toReturn = new cCow(); break;
|
||||||
case mtCreeper: toReturn = new cCreeper(); break;
|
case mtCreeper: toReturn = new cCreeper(); break;
|
||||||
|
case mtEnderDragon: toReturn = new cEnderDragon(); break;
|
||||||
case mtEnderman: toReturn = new cEnderman(); break;
|
case mtEnderman: toReturn = new cEnderman(); break;
|
||||||
case mtGhast: toReturn = new cGhast(); break;
|
case mtGhast: toReturn = new cGhast(); break;
|
||||||
|
case mtIronGolem: toReturn = new cIronGolem(); break;
|
||||||
case mtMooshroom: toReturn = new cMooshroom(); break;
|
case mtMooshroom: toReturn = new cMooshroom(); break;
|
||||||
case mtOcelot: toReturn = new cOcelot(); break;
|
case mtOcelot: toReturn = new cOcelot(); break;
|
||||||
case mtPig: toReturn = new cPig(); break;
|
case mtPig: toReturn = new cPig(); break;
|
||||||
case mtSheep: toReturn = new cSheep (Random.NextInt(15)); break; // Colour parameter
|
case mtSheep: toReturn = new cSheep (Random.NextInt(15)); break; // Colour parameter
|
||||||
case mtSilverfish: toReturn = new cSilverfish(); break;
|
case mtSilverfish: toReturn = new cSilverfish(); break;
|
||||||
|
case mtSnowGolem: toReturn = new cSnowGolem(); break;
|
||||||
case mtSpider: toReturn = new cSpider(); break;
|
case mtSpider: toReturn = new cSpider(); break;
|
||||||
case mtSquid: toReturn = new cSquid(); break;
|
case mtSquid: toReturn = new cSquid(); break;
|
||||||
case mtWitch: toReturn = new cWitch(); break;
|
case mtWitch: toReturn = new cWitch(); break;
|
||||||
|
case mtWither: toReturn = new cWither(); break;
|
||||||
case mtWolf: toReturn = new cWolf(); break;
|
case mtWolf: toReturn = new cWolf(); break;
|
||||||
case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter
|
case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter
|
||||||
case mtZombiePigman: toReturn = new cZombiePigman(); break;
|
case mtZombiePigman: toReturn = new cZombiePigman(); break;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
#include "SnowGolem.h"
|
#include "SnowGolem.h"
|
||||||
|
#include "../World.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,3 +25,21 @@ void cSnowGolem::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSnowGolem::Tick(float a_Dt, cChunk & a_Chunk)
|
||||||
|
{
|
||||||
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
if (IsBiomeNoDownfall((EMCSBiome) m_World->GetBiomeAt((int) floor(GetPosX()), (int) floor(GetPosZ())) ))
|
||||||
|
{
|
||||||
|
TakeDamage(*this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BLOCKTYPE BlockBelow = m_World->GetBlock((int) floor(GetPosX()), (int) floor(GetPosY()) - 1, (int) floor(GetPosZ()));
|
||||||
|
BLOCKTYPE Block = m_World->GetBlock((int) floor(GetPosX()), (int) floor(GetPosY()), (int) floor(GetPosZ()));
|
||||||
|
if (Block == E_BLOCK_AIR && g_BlockIsSolid[BlockBelow])
|
||||||
|
{
|
||||||
|
m_World->SetBlock((int) floor(GetPosX()), (int) floor(GetPosY()), (int) floor(GetPosZ()), E_BLOCK_SNOW, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ public:
|
||||||
|
|
||||||
CLASS_PROTODEF(cSnowGolem);
|
CLASS_PROTODEF(cSnowGolem);
|
||||||
|
|
||||||
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,9 @@ public:
|
||||||
class cCallback
|
class cCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// Force a virtual destructor in all subclasses:
|
||||||
|
virtual ~cCallback() {}
|
||||||
|
|
||||||
/// Called when data is received from the remote party
|
/// Called when data is received from the remote party
|
||||||
virtual void DataReceived(const char * a_Data, int a_Size) = 0;
|
virtual void DataReceived(const char * a_Data, int a_Size) = 0;
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ public:
|
||||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0;
|
virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0;
|
||||||
virtual void SendPlayerAbilities (void) = 0;
|
virtual void SendPlayerAbilities (void) = 0;
|
||||||
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) = 0;
|
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) = 0;
|
||||||
|
virtual void SendParticleEffect (const AString & a_SoundName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) = 0;
|
||||||
virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) = 0;
|
virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) = 0;
|
||||||
virtual void SendPlayerMaxSpeed (void) = 0; ///< Informs the client of the maximum player speed (1.6.1+)
|
virtual void SendPlayerMaxSpeed (void) = 0; ///< Informs the client of the maximum player speed (1.6.1+)
|
||||||
virtual void SendPlayerMoveLook (void) = 0;
|
virtual void SendPlayerMoveLook (void) = 0;
|
||||||
|
|
|
@ -608,6 +608,15 @@ void cProtocol125::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol125::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
|
||||||
|
{
|
||||||
|
// Not supported by this protocol version
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
|
void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSPacket);
|
cCSLock Lock(m_CSPacket);
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
||||||
virtual void SendKeepAlive (int a_PingID) override;
|
virtual void SendKeepAlive (int a_PingID) override;
|
||||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||||
|
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
|
||||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
||||||
virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
|
virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
|
||||||
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
|
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
|
||||||
|
|
|
@ -36,6 +36,7 @@ Implements the 1.5.x protocol classes:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PACKET_WINDOW_OPEN = 0x64,
|
PACKET_WINDOW_OPEN = 0x64,
|
||||||
|
PACKET_PARTICLE_EFFECT = 0x3F,
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,6 +77,26 @@ void cProtocol150::SendWindowOpen(const cWindow & a_Window)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol150::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSPacket);
|
||||||
|
WriteByte(PACKET_PARTICLE_EFFECT);
|
||||||
|
WriteString(a_ParticleName);
|
||||||
|
WriteFloat(a_SrcX);
|
||||||
|
WriteFloat(a_SrcY);
|
||||||
|
WriteFloat(a_SrcZ);
|
||||||
|
WriteFloat(a_OffsetX);
|
||||||
|
WriteFloat(a_OffsetY);
|
||||||
|
WriteFloat(a_OffsetZ);
|
||||||
|
WriteFloat(a_ParticleData);
|
||||||
|
WriteInt(a_ParticleAmmount);
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cProtocol150::ParseWindowClick(void)
|
int cProtocol150::ParseWindowClick(void)
|
||||||
{
|
{
|
||||||
HANDLE_PACKET_READ(ReadChar, char, WindowID);
|
HANDLE_PACKET_READ(ReadChar, char, WindowID);
|
||||||
|
|
|
@ -28,8 +28,9 @@ class cProtocol150 :
|
||||||
public:
|
public:
|
||||||
cProtocol150(cClientHandle * a_Client);
|
cProtocol150(cClientHandle * a_Client);
|
||||||
|
|
||||||
virtual void SendWindowOpen(const cWindow & a_Window) override;
|
virtual void SendWindowOpen (const cWindow & a_Window) override;
|
||||||
|
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
|
||||||
|
|
||||||
virtual int ParseWindowClick(void);
|
virtual int ParseWindowClick(void);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
|
@ -521,6 +521,24 @@ void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
|
||||||
|
{
|
||||||
|
cPacketizer Pkt(*this, 0x2A);
|
||||||
|
Pkt.WriteString(a_ParticleName);
|
||||||
|
Pkt.WriteFloat(a_SrcX);
|
||||||
|
Pkt.WriteFloat(a_SrcY);
|
||||||
|
Pkt.WriteFloat(a_SrcZ);
|
||||||
|
Pkt.WriteFloat(a_OffsetX);
|
||||||
|
Pkt.WriteFloat(a_OffsetY);
|
||||||
|
Pkt.WriteFloat(a_OffsetZ);
|
||||||
|
Pkt.WriteFloat(a_ParticleData);
|
||||||
|
Pkt.WriteInt(a_ParticleAmmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
|
void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
|
||||||
{
|
{
|
||||||
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
|
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
|
||||||
|
|
|
@ -66,6 +66,7 @@ public:
|
||||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
||||||
virtual void SendPlayerAbilities (void) override;
|
virtual void SendPlayerAbilities (void) override;
|
||||||
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
|
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
|
||||||
|
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
|
||||||
virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override;
|
virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override;
|
||||||
virtual void SendPlayerMaxSpeed (void) override;
|
virtual void SendPlayerMaxSpeed (void) override;
|
||||||
virtual void SendPlayerMoveLook (void) override;
|
virtual void SendPlayerMoveLook (void) override;
|
||||||
|
|
|
@ -386,6 +386,16 @@ void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_W
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocolRecognizer::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
|
||||||
|
{
|
||||||
|
ASSERT(m_Protocol != NULL);
|
||||||
|
m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cProtocolRecognizer::SendPickupSpawn(const cPickup & a_Pickup)
|
void cProtocolRecognizer::SendPickupSpawn(const cPickup & a_Pickup)
|
||||||
{
|
{
|
||||||
ASSERT(m_Protocol != NULL);
|
ASSERT(m_Protocol != NULL);
|
||||||
|
|
|
@ -89,6 +89,7 @@ public:
|
||||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
||||||
virtual void SendKeepAlive (int a_PingID) override;
|
virtual void SendKeepAlive (int a_PingID) override;
|
||||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||||
|
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
|
||||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
||||||
virtual void SendPlayerAbilities (void) override;
|
virtual void SendPlayerAbilities (void) override;
|
||||||
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
|
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
|
||||||
|
|
34
src/Root.cpp
34
src/Root.cpp
|
@ -22,6 +22,7 @@
|
||||||
#include "inifile/iniFile.h"
|
#include "inifile/iniFile.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
#include "conio.h"
|
||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -29,6 +30,8 @@
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern bool g_TERMINATE_EVENT_RAISED;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,7 +79,7 @@ void cRoot::InputThread(void * a_Params)
|
||||||
|
|
||||||
cLogCommandOutputCallback Output;
|
cLogCommandOutputCallback Output;
|
||||||
|
|
||||||
while (!(self.m_bStop || self.m_bRestart) && std::cin.good())
|
while (!self.m_bStop && !self.m_bRestart && !g_TERMINATE_EVENT_RAISED && std::cin.good())
|
||||||
{
|
{
|
||||||
AString Command;
|
AString Command;
|
||||||
std::getline(std::cin, Command);
|
std::getline(std::cin, Command);
|
||||||
|
@ -85,10 +88,10 @@ void cRoot::InputThread(void * a_Params)
|
||||||
self.ExecuteConsoleCommand(TrimString(Command), Output);
|
self.ExecuteConsoleCommand(TrimString(Command), Output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(self.m_bStop || self.m_bRestart))
|
if (g_TERMINATE_EVENT_RAISED || !std::cin.good())
|
||||||
{
|
{
|
||||||
// We have come here because the std::cin has received an EOF and the server is still running; stop the server:
|
// We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running; stop the server:
|
||||||
self.m_bStop = true;
|
self.m_bStop = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +102,12 @@ void cRoot::InputThread(void * a_Params)
|
||||||
|
|
||||||
void cRoot::Start(void)
|
void cRoot::Start(void)
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
HWND hwnd = GetConsoleWindow();
|
||||||
|
HMENU hmenu = GetSystemMenu(hwnd, FALSE);
|
||||||
|
EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling
|
||||||
|
#endif
|
||||||
|
|
||||||
cDeadlockDetect dd;
|
cDeadlockDetect dd;
|
||||||
delete m_Log;
|
delete m_Log;
|
||||||
m_Log = new cMCLogger();
|
m_Log = new cMCLogger();
|
||||||
|
@ -192,12 +201,20 @@ void cRoot::Start(void)
|
||||||
finishmseconds -= mseconds;
|
finishmseconds -= mseconds;
|
||||||
|
|
||||||
LOG("Startup complete, took %i ms!", finishmseconds);
|
LOG("Startup complete, took %i ms!", finishmseconds);
|
||||||
|
#ifdef _WIN32
|
||||||
|
EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
|
||||||
|
#endif
|
||||||
|
|
||||||
while (!m_bStop && !m_bRestart) // These are modified by external threads
|
while (!m_bStop && !m_bRestart && !g_TERMINATE_EVENT_RAISED) // These are modified by external threads
|
||||||
{
|
{
|
||||||
cSleep::MilliSleep(1000);
|
cSleep::MilliSleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_TERMINATE_EVENT_RAISED)
|
||||||
|
{
|
||||||
|
m_bStop = true;
|
||||||
|
}
|
||||||
|
|
||||||
#if !defined(ANDROID_NDK)
|
#if !defined(ANDROID_NDK)
|
||||||
delete m_InputThread; m_InputThread = NULL;
|
delete m_InputThread; m_InputThread = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
@ -222,7 +239,7 @@ void cRoot::Start(void)
|
||||||
delete m_FurnaceRecipe; m_FurnaceRecipe = NULL;
|
delete m_FurnaceRecipe; m_FurnaceRecipe = NULL;
|
||||||
delete m_CraftingRecipes; m_CraftingRecipes = NULL;
|
delete m_CraftingRecipes; m_CraftingRecipes = NULL;
|
||||||
LOGD("Forgetting groups...");
|
LOGD("Forgetting groups...");
|
||||||
delete m_GroupManager; m_GroupManager = 0;
|
delete m_GroupManager; m_GroupManager = NULL;
|
||||||
LOGD("Unloading worlds...");
|
LOGD("Unloading worlds...");
|
||||||
UnloadWorlds();
|
UnloadWorlds();
|
||||||
|
|
||||||
|
@ -233,12 +250,11 @@ void cRoot::Start(void)
|
||||||
cBlockHandler::Deinit();
|
cBlockHandler::Deinit();
|
||||||
|
|
||||||
LOG("Cleaning up...");
|
LOG("Cleaning up...");
|
||||||
//delete HeartBeat; HeartBeat = 0;
|
delete m_Server; m_Server = NULL;
|
||||||
delete m_Server; m_Server = 0;
|
|
||||||
LOG("Shutdown successful!");
|
LOG("Shutdown successful!");
|
||||||
}
|
}
|
||||||
|
|
||||||
delete m_Log; m_Log = 0;
|
delete m_Log; m_Log = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "../Blocks/BlockTorch.h"
|
#include "../Blocks/BlockTorch.h"
|
||||||
#include "../Blocks/BlockDoor.h"
|
#include "../Blocks/BlockDoor.h"
|
||||||
#include "../Piston.h"
|
#include "../Piston.h"
|
||||||
|
#include "../Tracer.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,21 +107,47 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
|
||||||
((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) ||
|
((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) ||
|
||||||
((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) ||
|
((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) ||
|
||||||
((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (SourceBlockMeta & 0x08) == 0x08) ||
|
((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (SourceBlockMeta & 0x08) == 0x08) ||
|
||||||
(((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta)))
|
(((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) ||
|
||||||
|
(((SourceBlockType == E_BLOCK_STONE_PRESSURE_PLATE) || (SourceBlockType == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (SourceBlockMeta == 0))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(itr->a_SourceBlock).c_str());
|
LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(itr->a_SourceBlock).c_str());
|
||||||
itr = m_PoweredBlocks.erase(itr);
|
itr = m_PoweredBlocks.erase(itr);
|
||||||
}
|
}
|
||||||
|
else if (SourceBlockType == E_BLOCK_DAYLIGHT_SENSOR)
|
||||||
|
{
|
||||||
|
if (!a_Chunk->IsLightValid())
|
||||||
|
{
|
||||||
|
m_World.QueueLightChunk(a_ChunkX, a_ChunkZ);
|
||||||
|
++itr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NIBBLETYPE SkyLight;
|
||||||
|
a_Chunk->UnboundedRelGetBlockSkyLight(RelX, itr->a_SourcePos.y + 1, RelZ, SkyLight);
|
||||||
|
|
||||||
|
if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness();
|
||||||
|
{
|
||||||
|
LOGD("cRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level");
|
||||||
|
itr = m_PoweredBlocks.erase(itr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++itr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else if ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (DestBlockType == E_BLOCK_REDSTONE_WIRE))
|
else if ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (DestBlockType == E_BLOCK_REDSTONE_WIRE))
|
||||||
{
|
{
|
||||||
// It is simply not allowed that a wire powers another wire, presuming that data here is sane and a dest and source are beside each other
|
// It is simply not allowed that a wire powers another wire, presuming that data here is sane and a dest and source are beside each other
|
||||||
LOGD("cRedstoneSimulator: Erased redstone wire from powered blocks list because it's source was also wire");
|
LOGD("cRedstoneSimulator: Erased redstone wire from powered blocks list because its source was also wire");
|
||||||
itr = m_PoweredBlocks.erase(itr);
|
itr = m_PoweredBlocks.erase(itr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
itr++;
|
++itr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +192,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
itr++;
|
++itr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +213,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
itr++;
|
++itr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,12 +233,8 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
|
||||||
itr = m_RepeatersDelayList.erase(itr);
|
itr = m_RepeatersDelayList.erase(itr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (itr->a_ElapsedTicks < itr->a_DelayTicks)
|
|
||||||
{
|
|
||||||
itr->a_ElapsedTicks++;
|
|
||||||
}
|
|
||||||
|
|
||||||
itr++;
|
++itr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;)
|
for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;)
|
||||||
|
@ -285,6 +308,12 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
|
||||||
HandleRail(a_X, dataitr->y, a_Z, BlockType);
|
HandleRail(a_X, dataitr->y, a_Z, BlockType);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case E_BLOCK_WOODEN_PRESSURE_PLATE:
|
||||||
|
case E_BLOCK_STONE_PRESSURE_PLATE:
|
||||||
|
{
|
||||||
|
HandlePressurePlate(a_X, dataitr->y, a_Z, BlockType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
++dataitr;
|
++dataitr;
|
||||||
|
@ -601,7 +630,7 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int
|
||||||
QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, false);
|
QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); itr++)
|
for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
|
||||||
{
|
{
|
||||||
if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
|
if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
|
||||||
{
|
{
|
||||||
|
@ -659,8 +688,14 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// Tick incrementing handled in SimChunk
|
{
|
||||||
|
// Apparently, incrementing ticks only works reliably here, and not in SimChunk;
|
||||||
|
// With a world with lots of redstone, the repeaters simply do not delay
|
||||||
|
// I am confounded to say why. Perhaps optimisation failure.
|
||||||
|
LOGD("Incremented a repeater @ %i %i %i | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
|
||||||
|
itr->a_ElapsedTicks++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -897,9 +932,112 @@ void cRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, int a_Block
|
||||||
|
|
||||||
void cRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ)
|
void cRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||||
{
|
{
|
||||||
if (m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) > 10)
|
int a_ChunkX, a_ChunkZ;
|
||||||
|
cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, a_ChunkX, a_ChunkZ);
|
||||||
|
|
||||||
|
if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ))
|
||||||
{
|
{
|
||||||
SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR);
|
m_World.QueueLightChunk(a_ChunkX, a_ChunkZ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NIBBLETYPE SkyLight = m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) - m_World.GetSkyDarkness();
|
||||||
|
if (SkyLight > 8)
|
||||||
|
{
|
||||||
|
SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
|
||||||
|
{
|
||||||
|
switch (a_MyType)
|
||||||
|
{
|
||||||
|
case E_BLOCK_STONE_PRESSURE_PLATE:
|
||||||
|
{
|
||||||
|
// MCS feature - stone pressure plates can only be triggered by players :D
|
||||||
|
cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(a_BlockX + 0.5f, (float)a_BlockY, a_BlockZ + 0.5f), 0.5f);
|
||||||
|
|
||||||
|
if (a_Player != NULL)
|
||||||
|
{
|
||||||
|
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
|
||||||
|
SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_STONE_PRESSURE_PLATE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case E_BLOCK_WOODEN_PRESSURE_PLATE:
|
||||||
|
{
|
||||||
|
class cWoodenPressurePlateCallback :
|
||||||
|
public cEntityCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cWoodenPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
|
||||||
|
m_X(a_BlockX),
|
||||||
|
m_Y(a_BlockY),
|
||||||
|
m_Z(a_BlockZ),
|
||||||
|
m_World(a_World),
|
||||||
|
m_Entity(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Item(cEntity * a_Entity) override
|
||||||
|
{
|
||||||
|
cTracer LineOfSight(m_World);
|
||||||
|
|
||||||
|
Vector3f EntityPos = a_Entity->GetPosition();
|
||||||
|
Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
|
||||||
|
float Distance = (EntityPos - BlockPos).Length();
|
||||||
|
|
||||||
|
if (Distance < 0.5)
|
||||||
|
{
|
||||||
|
if (!LineOfSight.Trace(BlockPos, (EntityPos - BlockPos), (int)(EntityPos - BlockPos).Length()))
|
||||||
|
{
|
||||||
|
m_Entity = a_Entity;
|
||||||
|
return true; // Break out, we only need to know for wooden plates that at least one entity is on top
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FoundEntity(void) const
|
||||||
|
{
|
||||||
|
return m_Entity != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
cEntity * m_Entity;
|
||||||
|
cWorld * m_World;
|
||||||
|
|
||||||
|
int m_X;
|
||||||
|
int m_Y;
|
||||||
|
int m_Z;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
cWoodenPressurePlateCallback WoodenPressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ, &m_World);
|
||||||
|
m_World.ForEachEntity(WoodenPressurePlateCallback);
|
||||||
|
|
||||||
|
if (WoodenPressurePlateCallback.FoundEntity())
|
||||||
|
{
|
||||||
|
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
|
||||||
|
SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WOODEN_PRESSURE_PLATE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1308,7 +1446,7 @@ void cRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a
|
||||||
|
|
||||||
void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn)
|
void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn)
|
||||||
{
|
{
|
||||||
for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); itr++)
|
for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
|
||||||
{
|
{
|
||||||
if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
|
if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
|
||||||
{
|
{
|
||||||
|
@ -1318,7 +1456,7 @@ void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, in
|
||||||
}
|
}
|
||||||
|
|
||||||
// Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit
|
// Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit
|
||||||
itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; // See below for description
|
itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2; // See below for description
|
||||||
itr->a_ElapsedTicks = 0;
|
itr->a_ElapsedTicks = 0;
|
||||||
itr->ShouldPowerOn = ShouldPowerOn;
|
itr->ShouldPowerOn = ShouldPowerOn;
|
||||||
return;
|
return;
|
||||||
|
@ -1331,7 +1469,8 @@ void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, in
|
||||||
|
|
||||||
// Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
|
// Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
|
||||||
// * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed
|
// * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed
|
||||||
RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2;
|
// We don't +1 when powering off because everything seems to already delay a tick when powering off, why? No idea :P
|
||||||
|
RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2;
|
||||||
|
|
||||||
|
|
||||||
RC.a_ElapsedTicks = 0;
|
RC.a_ElapsedTicks = 0;
|
||||||
|
|
|
@ -89,6 +89,10 @@ private:
|
||||||
void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ);
|
void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
/// <summary>Handles buttons</summary>
|
/// <summary>Handles buttons</summary>
|
||||||
void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType);
|
void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType);
|
||||||
|
/// <summary>Handles daylight sensors</summary>
|
||||||
|
void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
|
/// <summary>Handles pressure plates</summary>
|
||||||
|
void HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
|
||||||
/* ==================== */
|
/* ==================== */
|
||||||
|
|
||||||
/* ====== CARRIERS ====== */
|
/* ====== CARRIERS ====== */
|
||||||
|
@ -115,8 +119,6 @@ private:
|
||||||
void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ);
|
void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
/// <summary>Handles noteblocks</summary>
|
/// <summary>Handles noteblocks</summary>
|
||||||
void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
|
void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
/// <summary>Handles noteblocks</summary>
|
|
||||||
void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ);
|
|
||||||
/* ===================== */
|
/* ===================== */
|
||||||
|
|
||||||
/* ====== Helper functions ====== */
|
/* ====== Helper functions ====== */
|
||||||
|
|
|
@ -73,10 +73,10 @@
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
#include <windows.h>
|
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#pragma comment(lib, "version.lib") // for "VerQueryValue"
|
#pragma comment(lib, "version.lib") // for "VerQueryValue"
|
||||||
#pragma warning(disable:4826)
|
#pragma warning(disable:4826)
|
||||||
|
|
||||||
|
|
|
@ -100,10 +100,10 @@ bool cWebAdmin::Init(void)
|
||||||
|
|
||||||
LOGD("Initialising WebAdmin...");
|
LOGD("Initialising WebAdmin...");
|
||||||
|
|
||||||
AString PortsIPv4 = m_IniFile.GetValueSet("WebAdmin", "Port", "8080");
|
m_PortsIPv4 = m_IniFile.GetValueSet("WebAdmin", "Port", "8080");
|
||||||
AString PortsIPv6 = m_IniFile.GetValueSet("WebAdmin", "PortsIPv6", "");
|
m_PortsIPv6 = m_IniFile.GetValueSet("WebAdmin", "PortsIPv6", "");
|
||||||
|
|
||||||
if (!m_HTTPServer.Initialize(PortsIPv4, PortsIPv6))
|
if (!m_HTTPServer.Initialize(m_PortsIPv4, m_PortsIPv6))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,6 +132,9 @@ public:
|
||||||
/// Escapes text passed into it, so it can be embedded into html.
|
/// Escapes text passed into it, so it can be embedded into html.
|
||||||
static AString GetHTMLEscapedString(const AString & a_Input);
|
static AString GetHTMLEscapedString(const AString & a_Input);
|
||||||
|
|
||||||
|
AString GetIPv4Ports(void) const { return m_PortsIPv4; }
|
||||||
|
AString GetIPv6Ports(void) const { return m_PortsIPv6; }
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
/// Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style)
|
/// Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style)
|
||||||
|
@ -180,6 +183,9 @@ protected:
|
||||||
|
|
||||||
PluginList m_Plugins;
|
PluginList m_Plugins;
|
||||||
|
|
||||||
|
AString m_PortsIPv4;
|
||||||
|
AString m_PortsIPv6;
|
||||||
|
|
||||||
/// The Lua template script to provide templates:
|
/// The Lua template script to provide templates:
|
||||||
cLuaState m_TemplateScript;
|
cLuaState m_TemplateScript;
|
||||||
|
|
||||||
|
|
|
@ -1878,6 +1878,15 @@ void cWorld::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude)
|
||||||
|
{
|
||||||
|
m_ChunkMap->BroadcastParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount, a_Exclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude)
|
void cWorld::BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSPlayers);
|
cCSLock Lock(m_CSPlayers);
|
||||||
|
|
|
@ -162,6 +162,7 @@ public:
|
||||||
void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
|
void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
|
void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
|
||||||
|
void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL);
|
void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
|
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
|
||||||
void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8
|
void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8
|
||||||
|
@ -419,7 +420,7 @@ public:
|
||||||
a_SourceData exact type depends on the a_Source:
|
a_SourceData exact type depends on the a_Source:
|
||||||
| esOther | void * |
|
| esOther | void * |
|
||||||
| esPrimedTNT | cTNTEntity * |
|
| esPrimedTNT | cTNTEntity * |
|
||||||
| esCreeper | cCreeper * |
|
| esMonster | cMonster * |
|
||||||
| esBed | cVector3i * |
|
| esBed | cVector3i * |
|
||||||
| esEnderCrystal | Vector3i * |
|
| esEnderCrystal | Vector3i * |
|
||||||
| esGhastFireball | cGhastFireball * |
|
| esGhastFireball | cGhastFireball * |
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "NBTChunkSerializer.h"
|
#include "NBTChunkSerializer.h"
|
||||||
#include "../BlockID.h"
|
#include "../BlockID.h"
|
||||||
|
#include "../ItemGrid.h"
|
||||||
|
#include "../StringCompression.h"
|
||||||
|
#include "FastNBT.h"
|
||||||
|
|
||||||
#include "../BlockEntities/ChestEntity.h"
|
#include "../BlockEntities/ChestEntity.h"
|
||||||
#include "../BlockEntities/DispenserEntity.h"
|
#include "../BlockEntities/DispenserEntity.h"
|
||||||
#include "../BlockEntities/DropperEntity.h"
|
#include "../BlockEntities/DropperEntity.h"
|
||||||
|
@ -13,17 +17,27 @@
|
||||||
#include "../BlockEntities/JukeboxEntity.h"
|
#include "../BlockEntities/JukeboxEntity.h"
|
||||||
#include "../BlockEntities/NoteEntity.h"
|
#include "../BlockEntities/NoteEntity.h"
|
||||||
#include "../BlockEntities/SignEntity.h"
|
#include "../BlockEntities/SignEntity.h"
|
||||||
#include "../ItemGrid.h"
|
|
||||||
#include "../StringCompression.h"
|
|
||||||
#include "../Entities/Entity.h"
|
#include "../Entities/Entity.h"
|
||||||
#include "FastNBT.h"
|
|
||||||
#include "../Entities/FallingBlock.h"
|
#include "../Entities/FallingBlock.h"
|
||||||
#include "../Entities/Boat.h"
|
#include "../Entities/Boat.h"
|
||||||
#include "../Entities/Minecart.h"
|
#include "../Entities/Minecart.h"
|
||||||
#include "../Mobs/Monster.h"
|
|
||||||
#include "../Entities/Pickup.h"
|
#include "../Entities/Pickup.h"
|
||||||
#include "../Entities/ProjectileEntity.h"
|
#include "../Entities/ProjectileEntity.h"
|
||||||
|
|
||||||
|
#include "../Mobs/Monster.h"
|
||||||
|
#include "../Mobs/Bat.h"
|
||||||
|
#include "../Mobs/Creeper.h"
|
||||||
|
#include "../Mobs/Enderman.h"
|
||||||
|
#include "../Mobs/Horse.h"
|
||||||
|
#include "../Mobs/Magmacube.h"
|
||||||
|
#include "../Mobs/Sheep.h"
|
||||||
|
#include "../Mobs/Slime.h"
|
||||||
|
#include "../Mobs/Skeleton.h"
|
||||||
|
#include "../Mobs/Villager.h"
|
||||||
|
#include "../Mobs/Wolf.h"
|
||||||
|
#include "../Mobs/Zombie.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -322,7 +336,120 @@ void cNBTChunkSerializer::AddMinecartEntity(cMinecart * a_Minecart)
|
||||||
|
|
||||||
void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
|
void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
|
||||||
{
|
{
|
||||||
// TODO
|
const char * EntityClass = NULL;
|
||||||
|
switch (a_Monster->GetMobType())
|
||||||
|
{
|
||||||
|
case cMonster::mtBat: EntityClass = "Bat"; break;
|
||||||
|
case cMonster::mtBlaze: EntityClass = "Blaze"; break;
|
||||||
|
case cMonster::mtCaveSpider: EntityClass = "CaveSpider"; break;
|
||||||
|
case cMonster::mtChicken: EntityClass = "Chicken"; break;
|
||||||
|
case cMonster::mtCow: EntityClass = "Cow"; break;
|
||||||
|
case cMonster::mtCreeper: EntityClass = "Creeper"; break;
|
||||||
|
case cMonster::mtEnderDragon: EntityClass = "EnderDragon"; break;
|
||||||
|
case cMonster::mtEnderman: EntityClass = "Enderman"; break;
|
||||||
|
case cMonster::mtGhast: EntityClass = "Ghast"; break;
|
||||||
|
case cMonster::mtGiant: EntityClass = "Giant"; break;
|
||||||
|
case cMonster::mtHorse: EntityClass = "Horse"; break;
|
||||||
|
case cMonster::mtIronGolem: EntityClass = "VillagerGolem"; break;
|
||||||
|
case cMonster::mtMagmaCube: EntityClass = "LavaSlime"; break;
|
||||||
|
case cMonster::mtMooshroom: EntityClass = "MushroomCow"; break;
|
||||||
|
case cMonster::mtOcelot: EntityClass = "Ozelot"; break;
|
||||||
|
case cMonster::mtPig: EntityClass = "Pig"; break;
|
||||||
|
case cMonster::mtSheep: EntityClass = "Sheep"; break;
|
||||||
|
case cMonster::mtSilverfish: EntityClass = "Silverfish"; break;
|
||||||
|
case cMonster::mtSkeleton: EntityClass = "Skeleton"; break;
|
||||||
|
case cMonster::mtSlime: EntityClass = "Slime"; break;
|
||||||
|
case cMonster::mtSnowGolem: EntityClass = "SnowMan"; break;
|
||||||
|
case cMonster::mtSpider: EntityClass = "Spider"; break;
|
||||||
|
case cMonster::mtSquid: EntityClass = "Squid"; break;
|
||||||
|
case cMonster::mtVillager: EntityClass = "Villager"; break;
|
||||||
|
case cMonster::mtWitch: EntityClass = "Witch"; break;
|
||||||
|
case cMonster::mtWither: EntityClass = "Wither"; break;
|
||||||
|
case cMonster::mtWolf: EntityClass = "Wolf"; break;
|
||||||
|
case cMonster::mtZombie: EntityClass = "Zombie"; break;
|
||||||
|
case cMonster::mtZombiePigman: EntityClass = "PigZombie"; break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
ASSERT(!"Unhandled monster type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} // switch (payload)
|
||||||
|
|
||||||
|
m_Writer.BeginCompound("");
|
||||||
|
AddBasicEntity(a_Monster, EntityClass);
|
||||||
|
switch (a_Monster->GetMobType())
|
||||||
|
{
|
||||||
|
case cMonster::mtBat:
|
||||||
|
{
|
||||||
|
m_Writer.AddByte("BatFlags", ((const cBat *)a_Monster)->IsHanging());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMonster::mtCreeper:
|
||||||
|
{
|
||||||
|
m_Writer.AddByte("powered", ((const cCreeper *)a_Monster)->IsCharged());
|
||||||
|
m_Writer.AddByte("ignited", ((const cCreeper *)a_Monster)->IsBlowing());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMonster::mtEnderman:
|
||||||
|
{
|
||||||
|
m_Writer.AddShort("carried", (Int16)((const cEnderman *)a_Monster)->GetCarriedBlock());
|
||||||
|
m_Writer.AddShort("carriedData", (Int16)((const cEnderman *)a_Monster)->GetCarriedMeta());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMonster::mtHorse:
|
||||||
|
{
|
||||||
|
const cHorse & Horse = *((const cHorse *)a_Monster);
|
||||||
|
m_Writer.AddByte("ChestedHorse", Horse.IsChested());
|
||||||
|
m_Writer.AddByte("EatingHaystack", Horse.IsEating());
|
||||||
|
m_Writer.AddByte("Tame", Horse.IsTame());
|
||||||
|
m_Writer.AddInt ("Type", Horse.GetHorseType());
|
||||||
|
m_Writer.AddInt ("Color", Horse.GetHorseColor());
|
||||||
|
m_Writer.AddInt ("Style", Horse.GetHorseStyle());
|
||||||
|
m_Writer.AddInt ("ArmorType", Horse.GetHorseArmour());
|
||||||
|
m_Writer.AddByte("Saddle", Horse.IsSaddled());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMonster::mtMagmaCube:
|
||||||
|
{
|
||||||
|
m_Writer.AddByte("Size", ((const cMagmaCube *)a_Monster)->GetSize());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMonster::mtSheep:
|
||||||
|
{
|
||||||
|
m_Writer.AddByte("Sheared", ((const cSheep *)a_Monster)->IsSheared());
|
||||||
|
m_Writer.AddByte("Color", ((const cSheep *)a_Monster)->GetFurColor());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMonster::mtSlime:
|
||||||
|
{
|
||||||
|
m_Writer.AddInt("Size", ((const cSlime *)a_Monster)->GetSize());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMonster::mtSkeleton:
|
||||||
|
{
|
||||||
|
m_Writer.AddByte("SkeletonType", (((const cSkeleton *)a_Monster)->IsWither() ? 1 : 0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMonster::mtVillager:
|
||||||
|
{
|
||||||
|
m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMonster::mtWolf:
|
||||||
|
{
|
||||||
|
// TODO:
|
||||||
|
// _X: CopyPasta error: m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMonster::mtZombie:
|
||||||
|
{
|
||||||
|
m_Writer.AddByte("IsVillager", (((const cZombie *)a_Monster)->IsVillagerZombie() ? 1 : 0));
|
||||||
|
m_Writer.AddByte("IsBaby", (((const cZombie *)a_Monster)->IsBaby() ? 1 : 0));
|
||||||
|
m_Writer.AddByte("IsConverting", (((const cZombie *)a_Monster)->IsConverting() ? 1 : 0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_Writer.EndCompound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -479,6 +606,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
|
||||||
case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
|
case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
|
||||||
case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
|
case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
|
||||||
case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break;
|
case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break;
|
||||||
|
case cEntity::etExpOrb: /* TODO */ break;
|
||||||
case cEntity::etPlayer: return; // Players aren't saved into the world
|
case cEntity::etPlayer: return; // Players aren't saved into the world
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,9 +6,14 @@
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "WSSAnvil.h"
|
#include "WSSAnvil.h"
|
||||||
#include "NBTChunkSerializer.h"
|
#include "NBTChunkSerializer.h"
|
||||||
#include "../World.h"
|
#include "FastNBT.h"
|
||||||
#include "zlib/zlib.h"
|
#include "zlib/zlib.h"
|
||||||
|
#include "../World.h"
|
||||||
#include "../BlockID.h"
|
#include "../BlockID.h"
|
||||||
|
#include "../Item.h"
|
||||||
|
#include "../ItemGrid.h"
|
||||||
|
#include "../StringCompression.h"
|
||||||
|
|
||||||
#include "../BlockEntities/ChestEntity.h"
|
#include "../BlockEntities/ChestEntity.h"
|
||||||
#include "../BlockEntities/DispenserEntity.h"
|
#include "../BlockEntities/DispenserEntity.h"
|
||||||
#include "../BlockEntities/DropperEntity.h"
|
#include "../BlockEntities/DropperEntity.h"
|
||||||
|
@ -17,11 +22,11 @@
|
||||||
#include "../BlockEntities/JukeboxEntity.h"
|
#include "../BlockEntities/JukeboxEntity.h"
|
||||||
#include "../BlockEntities/NoteEntity.h"
|
#include "../BlockEntities/NoteEntity.h"
|
||||||
#include "../BlockEntities/SignEntity.h"
|
#include "../BlockEntities/SignEntity.h"
|
||||||
#include "../Item.h"
|
|
||||||
#include "../ItemGrid.h"
|
|
||||||
#include "../StringCompression.h"
|
|
||||||
#include "FastNBT.h"
|
|
||||||
#include "../Mobs/Monster.h"
|
#include "../Mobs/Monster.h"
|
||||||
|
#include "../Mobs/IncludeAllMonsters.h"
|
||||||
|
|
||||||
#include "../Entities/Boat.h"
|
#include "../Entities/Boat.h"
|
||||||
#include "../Entities/FallingBlock.h"
|
#include "../Entities/FallingBlock.h"
|
||||||
#include "../Entities/Minecart.h"
|
#include "../Entities/Minecart.h"
|
||||||
|
@ -984,6 +989,122 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
|
||||||
{
|
{
|
||||||
LoadThrownEnderpearlFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
LoadThrownEnderpearlFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
}
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Bat", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadBatFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Blaze", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadBlazeFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "CaveSpider", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadCaveSpiderFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Chicken", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadChickenFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Cow", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadCowFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Creeper", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadCreeperFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "EnderDragon", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadEnderDragonFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Enderman", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadEndermanFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Ghast", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadGhastFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Giant", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadGiantFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Horse", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadHorseFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "VillagerGolem", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadIronGolemFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "LavaSlime", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadMagmaCubeFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "MushroomCow", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadMooshroomFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Ozelot", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadOcelotFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Pig", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadPigFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Sheep", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadSheepFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Silverfish", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadSilverfishFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Skeleton", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadSkeletonFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Slime", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadSlimeFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "SnowMan", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadSnowGolemFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Spider", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadSpiderFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Squid", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadSquidFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Villager", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadVillagerFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Witch", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadWitchFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Wither", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadWitherFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Wolf", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadWolfFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "Zombie", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadZombieFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
|
else if (strncmp(a_IDTag, "PigZombie", a_IDTagLength) == 0)
|
||||||
|
{
|
||||||
|
LoadPigZombieFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||||
|
}
|
||||||
// TODO: other entities
|
// TODO: other entities
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1007,7 +1128,20 @@ void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
|
||||||
|
|
||||||
void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
{
|
{
|
||||||
// TODO
|
int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "TileID");
|
||||||
|
int MetaIdx = a_NBT.FindChildByName(a_TagIdx, "Data");
|
||||||
|
|
||||||
|
if ((TypeIdx < 0) || (MetaIdx < 0)) { return; }
|
||||||
|
|
||||||
|
int Type = a_NBT.GetInt(TypeIdx);
|
||||||
|
NIBBLETYPE Meta = (NIBBLETYPE)a_NBT.GetByte(MetaIdx);
|
||||||
|
|
||||||
|
std::auto_ptr<cFallingBlock> FallingBlock(new cFallingBlock(Vector3i(0, 0, 0), Type, Meta));
|
||||||
|
if (!LoadEntityBaseFromNBT(*FallingBlock.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
a_Entities.push_back(FallingBlock.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1254,6 +1388,488 @@ void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cPar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cBat> Monster(new cBat());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cBlaze> Monster(new cBlaze());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cCavespider> Monster(new cCavespider());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cChicken> Monster(new cChicken());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cCow> Monster(new cCow());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cCreeper> Monster(new cCreeper());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cEnderDragon> Monster(new cEnderDragon());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cEnderman> Monster(new cEnderman());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cGhast> Monster(new cGhast());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cGiant> Monster(new cGiant());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Type");
|
||||||
|
int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color");
|
||||||
|
int StyleIdx = a_NBT.FindChildByName(a_TagIdx, "Style");
|
||||||
|
|
||||||
|
if ((TypeIdx < 0) || (ColorIdx < 0) || (StyleIdx < 0)) { return; }
|
||||||
|
|
||||||
|
int Type = a_NBT.GetInt(TypeIdx);
|
||||||
|
int Color = a_NBT.GetInt(ColorIdx);
|
||||||
|
int Style = a_NBT.GetInt(StyleIdx);
|
||||||
|
|
||||||
|
std::auto_ptr<cHorse> Monster(new cHorse(Type, Color, Style, 1));
|
||||||
|
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadIronGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cIronGolem> Monster(new cIronGolem());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size");
|
||||||
|
|
||||||
|
if (SizeIdx < 0) { return; }
|
||||||
|
|
||||||
|
int Size = a_NBT.GetInt(SizeIdx);
|
||||||
|
|
||||||
|
std::auto_ptr<cMagmaCube> Monster(new cMagmaCube(Size));
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cMooshroom> Monster(new cMooshroom());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cOcelot> Monster(new cOcelot());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cPig> Monster(new cPig());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color");
|
||||||
|
|
||||||
|
if (ColorIdx < 0) { return; }
|
||||||
|
|
||||||
|
int Color = (int)a_NBT.GetByte(ColorIdx);
|
||||||
|
|
||||||
|
std::auto_ptr<cSheep> Monster(new cSheep(Color));
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cSilverfish> Monster(new cSilverfish());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "SkeletonType");
|
||||||
|
|
||||||
|
if (TypeIdx < 0) { return; }
|
||||||
|
|
||||||
|
bool Type = ((a_NBT.GetByte(TypeIdx) == 1) ? true : false);
|
||||||
|
|
||||||
|
std::auto_ptr<cSkeleton> Monster(new cSkeleton(Type));
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size");
|
||||||
|
|
||||||
|
if (SizeIdx < 0) { return; }
|
||||||
|
|
||||||
|
int Size = a_NBT.GetInt(SizeIdx);
|
||||||
|
|
||||||
|
std::auto_ptr<cSlime> Monster(new cSlime(Size));
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cSnowGolem> Monster(new cSnowGolem());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cSpider> Monster(new cSpider());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cSquid> Monster(new cSquid());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Profession");
|
||||||
|
|
||||||
|
if (TypeIdx < 0) { return; }
|
||||||
|
|
||||||
|
int Type = a_NBT.GetInt(TypeIdx);
|
||||||
|
|
||||||
|
std::auto_ptr<cVillager> Monster(new cVillager(cVillager::eVillagerType(Type)));
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cWitch> Monster(new cWitch());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cWither> Monster(new cWither());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cWolf> Monster(new cWolf());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
int IsVillagerIdx = a_NBT.FindChildByName(a_TagIdx, "IsVillager");
|
||||||
|
|
||||||
|
if (IsVillagerIdx < 0) { return; }
|
||||||
|
|
||||||
|
bool IsVillagerZombie = ((a_NBT.GetByte(IsVillagerIdx) == 1) ? true : false);
|
||||||
|
|
||||||
|
std::auto_ptr<cZombie> Monster(new cZombie(IsVillagerZombie));
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
std::auto_ptr<cZombiePigman> Monster(new cZombiePigman());
|
||||||
|
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Entities.push_back(Monster.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
|
bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
{
|
{
|
||||||
double Pos[3];
|
double Pos[3];
|
||||||
|
|
|
@ -142,18 +142,50 @@ protected:
|
||||||
|
|
||||||
void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
|
||||||
void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadMinecartFFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadMinecartFFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
|
||||||
void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadSnowballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadSnowballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadEggFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadEggFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadFireballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadFireballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadFireChargeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadFireChargeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
void LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
void LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
|
||||||
|
void LoadBatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadBlazeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadCaveSpiderFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadChickenFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadCowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadCreeperFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadEnderDragonFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadEndermanFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadGhastFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadGiantFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadHorseFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadIronGolemFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadMagmaCubeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadMooshroomFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadOcelotFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadPigFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadSheepFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadSilverfishFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadSkeletonFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadSlimeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadSnowGolemFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadSpiderFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadSquidFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadVillagerFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadWitchFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadWitherFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadWolfFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
void LoadPigZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
|
||||||
/// Loads entity common data from the NBT compound; returns true if successful
|
/// Loads entity common data from the NBT compound; returns true if successful
|
||||||
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);
|
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
|
64
src/main.cpp
64
src/main.cpp
|
@ -11,6 +11,10 @@
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
// Here, we have some ALL CAPS variables, to give the impression that this is deeeep, gritty programming :P
|
||||||
|
bool g_TERMINATE_EVENT_RAISED = false; // If something has told the server to stop; checked periodically in cRoot
|
||||||
|
bool g_SERVER_TERMINATED = false; // Set to true when the server terminates, so our CTRL handler can then tell Windows to close the console
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,14 +37,21 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void NonCtrlHandler(int a_Signal)
|
||||||
void ShowCrashReport(int)
|
|
||||||
{
|
{
|
||||||
std::signal(SIGSEGV, SIG_DFL);
|
LOGD("Terminate event raised from std::signal");
|
||||||
|
g_TERMINATE_EVENT_RAISED = true;
|
||||||
|
|
||||||
printf("\n\nMCServer has crashed!\n");
|
switch (a_Signal)
|
||||||
|
{
|
||||||
exit(-1);
|
case SIGSEGV:
|
||||||
|
{
|
||||||
|
std::signal(SIGSEGV, SIG_DFL);
|
||||||
|
LOGWARN("Segmentation fault; MCServer has crashed :(");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,13 +122,33 @@ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_Except
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Handle CTRL events in windows, including console window close
|
||||||
|
BOOL CtrlHandler(DWORD fdwCtrlType)
|
||||||
|
{
|
||||||
|
g_TERMINATE_EVENT_RAISED = true;
|
||||||
|
LOGD("Terminate event raised from the Windows CtrlHandler");
|
||||||
|
|
||||||
|
if (fdwCtrlType == CTRL_CLOSE_EVENT) // Console window closed via 'x' button, Windows will try to close immediately, therefore...
|
||||||
|
{
|
||||||
|
while (!g_SERVER_TERMINATED) { cSleep::MilliSleep(100); } // Delay as much as possible to try to get the server to shut down cleanly
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// main:
|
// main:
|
||||||
|
|
||||||
int main( int argc, char **argv )
|
int main( int argc, char **argv )
|
||||||
{
|
{
|
||||||
(void)argc;
|
UNUSED(argc);
|
||||||
(void)argv;
|
UNUSED(argv);
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
||||||
InitLeakFinder();
|
InitLeakFinder();
|
||||||
|
@ -149,6 +180,13 @@ int main( int argc, char **argv )
|
||||||
}
|
}
|
||||||
#endif // _WIN32 && !_WIN64
|
#endif // _WIN32 && !_WIN64
|
||||||
// End of dump-file magic
|
// End of dump-file magic
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE))
|
||||||
|
{
|
||||||
|
LOGERROR("Could not install the Windows CTRL handler!");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_DEBUG) && defined(_MSC_VER)
|
#if defined(_DEBUG) && defined(_MSC_VER)
|
||||||
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
|
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
|
||||||
|
@ -160,7 +198,9 @@ int main( int argc, char **argv )
|
||||||
#endif // _DEBUG && _MSC_VER
|
#endif // _DEBUG && _MSC_VER
|
||||||
|
|
||||||
#ifndef _DEBUG
|
#ifndef _DEBUG
|
||||||
std::signal(SIGSEGV, ShowCrashReport);
|
std::signal(SIGSEGV, NonCtrlHandler);
|
||||||
|
std::signal(SIGTERM, NonCtrlHandler);
|
||||||
|
std::signal(SIGINT, NonCtrlHandler);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DEBUG: test the dumpfile creation:
|
// DEBUG: test the dumpfile creation:
|
||||||
|
@ -188,8 +228,10 @@ int main( int argc, char **argv )
|
||||||
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
||||||
DeinitLeakFinder();
|
DeinitLeakFinder();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
g_SERVER_TERMINATED = true;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
cloc --by-file-by-lang --exclude-dir=source/SQLite,source/LuaExpat,doxy,tolua..-1.0.93,jsoncpp.*,lua-5.1.4,squirrel_3.* --exclude-list-file=cloc-exclude.txt --xml --xsl=1 --report-file=cloc.xml --ignored=cloc-ignored.txt .
|
cloc --by-file-by-lang --exclude-dir=lib --exclude-list-file=cloc-exclude.txt --xml --xsl=1 --report-file=cloc.xml --ignored=cloc-ignored.txt .
|
||||||
|
|
Loading…
Reference in New Issue