From 62ae7adab2bebde04864c12543caefbffab24963 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 15 Apr 2020 16:27:40 +0200 Subject: Android: add Android Studio support, completely redone java part (#9066) --- build/android/native/build.gradle | 59 ++++++ build/android/native/jni/Android.mk | 218 ++++++++++++++++++++++ build/android/native/jni/Application.mk | 32 ++++ build/android/native/src/main/AndroidManifest.xml | 1 + 4 files changed, 310 insertions(+) create mode 100644 build/android/native/build.gradle create mode 100644 build/android/native/jni/Android.mk create mode 100644 build/android/native/jni/Application.mk create mode 100644 build/android/native/src/main/AndroidManifest.xml (limited to 'build/android/native') diff --git a/build/android/native/build.gradle b/build/android/native/build.gradle new file mode 100644 index 000000000..f06e4e3f0 --- /dev/null +++ b/build/android/native/build.gradle @@ -0,0 +1,59 @@ +apply plugin: 'com.android.library' +import org.ajoberstar.grgit.Grgit + +android { + compileSdkVersion 29 + buildToolsVersion '29.0.3' + ndkVersion '21.0.6113669' + defaultConfig { + minSdkVersion 16 + targetSdkVersion 29 + externalNativeBuild { + ndkBuild { + arguments '-j8', + "versionMajor=${versionMajor}", + "versionMinor=${versionMinor}", + "versionPatch=${versionPatch}", + "versionExtra=${versionExtra}" + } + } + } + + externalNativeBuild { + ndkBuild { + path file('jni/Android.mk') + } + } + + // supported architectures + splits { + abi { + enable true + reset() + include 'armeabi-v7a', 'arm64-v8a'//, 'x86' + } + } + + buildTypes { + release { + externalNativeBuild { + ndkBuild { + arguments 'NDEBUG=1' + } + } + } + } +} + +task cloneGitRepo() { + def destination = file('deps') + if(!destination.exists()) { + def grgit = Grgit.clone( + dir: destination, + uri: 'https://github.com/minetest/minetest_android_deps_binaries' + ) + grgit.close() + } +} + +preBuild.dependsOn cloneGitRepo diff --git a/build/android/native/jni/Android.mk b/build/android/native/jni/Android.mk new file mode 100644 index 000000000..a5cb099e6 --- /dev/null +++ b/build/android/native/jni/Android.mk @@ -0,0 +1,218 @@ +LOCAL_PATH := $(call my-dir)/.. + +#LOCAL_ADDRESS_SANITIZER:=true + +include $(CLEAR_VARS) +LOCAL_MODULE := Curl +LOCAL_SRC_FILES := deps/Android/Curl/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libcurl.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := Freetype +LOCAL_SRC_FILES := deps/Android/Freetype/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libfreetype.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := Irrlicht +LOCAL_SRC_FILES := deps/Android/Irrlicht/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libIrrlicht.a +include $(PREBUILT_STATIC_LIBRARY) + +#include $(CLEAR_VARS) +#LOCAL_MODULE := LevelDB +#LOCAL_SRC_FILES := deps/Android/LevelDB/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libleveldb.a +#include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := LuaJIT +LOCAL_SRC_FILES := deps/Android/LuaJIT/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libluajit.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := mbedTLS +LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedtls.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := mbedx509 +LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedx509.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := mbedcrypto +LOCAL_SRC_FILES := deps/Android/mbedTLS/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libmbedcrypto.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := OpenAL +LOCAL_SRC_FILES := deps/Android/OpenAL-Soft/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libopenal.a +include $(PREBUILT_STATIC_LIBRARY) + +# You can use `OpenSSL and Crypto` instead `mbedTLS mbedx509 mbedcrypto`, +#but it increase APK size on ~0.7MB +#include $(CLEAR_VARS) +#LOCAL_MODULE := OpenSSL +#LOCAL_SRC_FILES := deps/Android/OpenSSL/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libssl.a +#include $(PREBUILT_STATIC_LIBRARY) + +#include $(CLEAR_VARS) +#LOCAL_MODULE := Crypto +#LOCAL_SRC_FILES := deps/Android/OpenSSL/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libcrypto.a +#include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := Vorbis +LOCAL_SRC_FILES := deps/Android/Vorbis/${NDK_TOOLCHAIN_VERSION}/$(APP_ABI)/libvorbis.a +include $(PREBUILT_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := Minetest + +LOCAL_CFLAGS += \ + -DJSONCPP_NO_LOCALE_SUPPORT \ + -DHAVE_TOUCHSCREENGUI \ + -DENABLE_GLES=1 \ + -DUSE_CURL=1 \ + -DUSE_SOUND=1 \ + -DUSE_FREETYPE=1 \ + -DUSE_LEVELDB=0 \ + -DUSE_LUAJIT=1 \ + -DVERSION_MAJOR=${versionMajor} \ + -DVERSION_MINOR=${versionMinor} \ + -DVERSION_PATCH=${versionPatch} \ + -DVERSION_EXTRA=${versionExtra} \ + $(GPROF_DEF) + +ifdef NDEBUG + LOCAL_CFLAGS += -DNDEBUG=1 +endif + +ifdef GPROF + GPROF_DEF := -DGPROF + PROFILER_LIBS := android-ndk-profiler + LOCAL_CFLAGS += -pg +endif + +LOCAL_C_INCLUDES := \ + ../../../src \ + ../../../src/script \ + ../../../lib/gmp \ + ../../../lib/jsoncpp \ + deps/Android/Curl/include \ + deps/Android/Freetype/include \ + deps/Android/Irrlicht/include \ + deps/Android/LevelDB/include \ + deps/Android/libiconv/include \ + deps/Android/libiconv/libcharset/include \ + deps/Android/LuaJIT/src \ + deps/Android/OpenAL-Soft/include \ + deps/Android/sqlite \ + deps/Android/Vorbis/include + +LOCAL_SRC_FILES := \ + $(wildcard ../../../src/client/*.cpp) \ + $(wildcard ../../../src/client/*/*.cpp) \ + $(wildcard ../../../src/content/*.cpp) \ + ../../../src/database/database.cpp \ + ../../../src/database/database-dummy.cpp \ + ../../../src/database/database-files.cpp \ + ../../../src/database/database-sqlite3.cpp \ + $(wildcard ../../../src/gui/*.cpp) \ + $(wildcard ../../../src/irrlicht_changes/*.cpp) \ + $(wildcard ../../../src/mapgen/*.cpp) \ + $(wildcard ../../../src/network/*.cpp) \ + $(wildcard ../../../src/script/*.cpp) \ + $(wildcard ../../../src/script/*/*.cpp) \ + $(wildcard ../../../src/server/*.cpp) \ + $(wildcard ../../../src/threading/*.cpp) \ + $(wildcard ../../../src/util/*.c) \ + $(wildcard ../../../src/util/*.cpp) \ + ../../../src/ban.cpp \ + ../../../src/chat.cpp \ + ../../../src/clientiface.cpp \ + ../../../src/collision.cpp \ + ../../../src/content_mapnode.cpp \ + ../../../src/content_nodemeta.cpp \ + ../../../src/convert_json.cpp \ + ../../../src/craftdef.cpp \ + ../../../src/debug.cpp \ + ../../../src/defaultsettings.cpp \ + ../../../src/emerge.cpp \ + ../../../src/environment.cpp \ + ../../../src/face_position_cache.cpp \ + ../../../src/filesys.cpp \ + ../../../src/gettext.cpp \ + ../../../src/httpfetch.cpp \ + ../../../src/hud.cpp \ + ../../../src/inventory.cpp \ + ../../../src/inventorymanager.cpp \ + ../../../src/itemdef.cpp \ + ../../../src/itemstackmetadata.cpp \ + ../../../src/light.cpp \ + ../../../src/log.cpp \ + ../../../src/main.cpp \ + ../../../src/map.cpp \ + ../../../src/map_settings_manager.cpp \ + ../../../src/mapblock.cpp \ + ../../../src/mapnode.cpp \ + ../../../src/mapsector.cpp \ + ../../../src/metadata.cpp \ + ../../../src/modchannels.cpp \ + ../../../src/nameidmapping.cpp \ + ../../../src/nodedef.cpp \ + ../../../src/nodemetadata.cpp \ + ../../../src/nodetimer.cpp \ + ../../../src/noise.cpp \ + ../../../src/objdef.cpp \ + ../../../src/object_properties.cpp \ + ../../../src/pathfinder.cpp \ + ../../../src/player.cpp \ + ../../../src/porting.cpp \ + ../../../src/porting_android.cpp \ + ../../../src/profiler.cpp \ + ../../../src/raycast.cpp \ + ../../../src/reflowscan.cpp \ + ../../../src/remoteplayer.cpp \ + ../../../src/rollback.cpp \ + ../../../src/rollback_interface.cpp \ + ../../../src/serialization.cpp \ + ../../../src/server.cpp \ + ../../../src/serverenvironment.cpp \ + ../../../src/serverlist.cpp \ + ../../../src/settings.cpp \ + ../../../src/staticobject.cpp \ + ../../../src/texture_override.cpp \ + ../../../src/tileanimation.cpp \ + ../../../src/tool.cpp \ + ../../../src/translation.cpp \ + ../../../src/version.cpp \ + ../../../src/voxel.cpp \ + ../../../src/voxelalgorithms.cpp + +# LevelDB backend is disabled +# ../../../src/database/database-leveldb.cpp + +# GMP +LOCAL_SRC_FILES += ../../../lib/gmp/mini-gmp.c + +# JSONCPP +LOCAL_SRC_FILES += ../../../lib/jsoncpp/jsoncpp.cpp + +# iconv +LOCAL_SRC_FILES += \ + deps/Android/libiconv/lib/iconv.c \ + deps/Android/libiconv/libcharset/lib/localcharset.c + +# SQLite3 +LOCAL_SRC_FILES += deps/Android/sqlite/sqlite3.c + +LOCAL_STATIC_LIBRARIES += Curl Freetype Irrlicht OpenAL mbedTLS mbedx509 mbedcrypto Vorbis LuaJIT android_native_app_glue $(PROFILER_LIBS) #LevelDB +#OpenSSL Crypto + +LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES + +include $(BUILD_SHARED_LIBRARY) + +ifdef GPROF +$(call import-module,android-ndk-profiler) +endif +$(call import-module,android/native_app_glue) diff --git a/build/android/native/jni/Application.mk b/build/android/native/jni/Application.mk new file mode 100644 index 000000000..82f0148f0 --- /dev/null +++ b/build/android/native/jni/Application.mk @@ -0,0 +1,32 @@ +APP_PLATFORM := ${APP_PLATFORM} +APP_ABI := ${TARGET_ABI} +APP_STL := c++_shared +NDK_TOOLCHAIN_VERSION := clang +APP_SHORT_COMMANDS := true +APP_MODULES := Minetest + +APP_CPPFLAGS := -Ofast -fvisibility=hidden -fexceptions -Wno-deprecated-declarations -Wno-extra-tokens + +ifeq ($(APP_ABI),armeabi-v7a) +APP_CPPFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb +endif + +#ifeq ($(APP_ABI),x86) +#APP_CPPFLAGS += -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32 -funroll-loops +#endif + +ifndef NDEBUG +APP_CPPFLAGS := -g -D_DEBUG -O0 -fno-omit-frame-pointer -fexceptions +endif + +APP_CFLAGS := $(APP_CPPFLAGS) -Wno-parentheses-equality #-Werror=shorten-64-to-32 +APP_CXXFLAGS := $(APP_CPPFLAGS) -frtti -std=gnu++17 +APP_LDFLAGS := -Wl,--no-warn-mismatch,--gc-sections,--icf=safe + +ifeq ($(APP_ABI),arm64-v8a) +APP_LDFLAGS := -Wl,--no-warn-mismatch,--gc-sections +endif + +ifndef NDEBUG +APP_LDFLAGS := +endif diff --git a/build/android/native/src/main/AndroidManifest.xml b/build/android/native/src/main/AndroidManifest.xml new file mode 100644 index 000000000..19451c7fd --- /dev/null +++ b/build/android/native/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + -- cgit v1.2.3 From 373bad16c089cd23448e8ce20b474e8fcf5b0c8b Mon Sep 17 00:00:00 2001 From: Maksim Date: Mon, 4 May 2020 08:47:00 +0200 Subject: Android: some java-part improvements (#9760) Replace Log to Toast. Start Native only after successful unpacking. Light refactoring in CopyZipTask. Update NDK version. Co-authored-by: ubulem --- build/android/app/build.gradle | 5 ++--- build/android/app/src/main/AndroidManifest.xml | 7 +++++++ .../src/main/java/net/minetest/minetest/CopyZipTask.java | 15 ++++----------- .../src/main/java/net/minetest/minetest/MainActivity.java | 13 ++++++++++--- .../src/main/java/net/minetest/minetest/UnzipService.java | 15 ++++++++------- build/android/native/build.gradle | 2 +- 6 files changed, 32 insertions(+), 25 deletions(-) (limited to 'build/android/native') diff --git a/build/android/app/build.gradle b/build/android/app/build.gradle index 9d14cdab8..00b8806bf 100644 --- a/build/android/app/build.gradle +++ b/build/android/app/build.gradle @@ -2,12 +2,11 @@ apply plugin: 'com.android.application' android { compileSdkVersion 29 buildToolsVersion '29.0.3' - ndkVersion '21.0.6113669' + ndkVersion '21.1.6352462' defaultConfig { applicationId 'net.minetest.minetest' minSdkVersion 16 - //noinspection OldTargetApi - targetSdkVersion 28 // Workaround for using `/sdcard` instead of the `data` patch for assets + targetSdkVersion 29 versionName "${versionMajor}.${versionMinor}.${versionPatch}" versionCode project.versionCode } diff --git a/build/android/app/src/main/AndroidManifest.xml b/build/android/app/src/main/AndroidManifest.xml index 3a5342751..aa5af110e 100644 --- a/build/android/app/src/main/AndroidManifest.xml +++ b/build/android/app/src/main/AndroidManifest.xml @@ -7,11 +7,18 @@ + + { } protected String doInBackground(String... params) { - copyAssets(params); + copyAsset(params[0]); return params[0]; } @@ -49,20 +49,13 @@ public class CopyZipTask extends AsyncTask { startUnzipService(result); } - private void copyAsset(String zipName) throws IOException { + private void copyAsset(String zipName) { String filename = zipName.substring(zipName.lastIndexOf("/") + 1); try (InputStream in = contextRef.get().getAssets().open(filename); OutputStream out = new FileOutputStream(zipName)) { copyFile(in, out); - } - } - - private void copyAssets(String[] zips) { - try { - for (String zipName : zips) - copyAsset(zipName); } catch (IOException e) { - Log.e("CopyZipTask", e.getLocalizedMessage()); + Toast.makeText(contextRef.get(), e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); cancel(true); } } diff --git a/build/android/app/src/main/java/net/minetest/minetest/MainActivity.java b/build/android/app/src/main/java/net/minetest/minetest/MainActivity.java index f37ae6d4b..1e60beb55 100644 --- a/build/android/app/src/main/java/net/minetest/minetest/MainActivity.java +++ b/build/android/app/src/main/java/net/minetest/minetest/MainActivity.java @@ -43,6 +43,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import static net.minetest.minetest.UnzipService.ACTION_PROGRESS; +import static net.minetest.minetest.UnzipService.ACTION_UPDATE; +import static net.minetest.minetest.UnzipService.FAILURE; +import static net.minetest.minetest.UnzipService.SUCCESS; + public class MainActivity extends AppCompatActivity { private final static int versionCode = BuildConfig.VERSION_CODE; private final static int PERMISSIONS = 1; @@ -58,14 +63,16 @@ public class MainActivity extends AppCompatActivity { public void onReceive(Context context, Intent intent) { int progress = 0; if (intent != null) - progress = intent.getIntExtra(UnzipService.ACTION_PROGRESS, 0); + progress = intent.getIntExtra(ACTION_PROGRESS, 0); if (progress >= 0) { if (mProgressBar != null) { mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setProgress(progress); } mTextView.setVisibility(View.VISIBLE); - } else + } else if (progress == FAILURE) { + finish(); + } else if (progress == SUCCESS) startNative(); } }; @@ -74,7 +81,7 @@ public class MainActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - IntentFilter filter = new IntentFilter(UnzipService.ACTION_UPDATE); + IntentFilter filter = new IntentFilter(ACTION_UPDATE); registerReceiver(myReceiver, filter); mProgressBar = findViewById(R.id.progressBar); mTextView = findViewById(R.id.textView); diff --git a/build/android/app/src/main/java/net/minetest/minetest/UnzipService.java b/build/android/app/src/main/java/net/minetest/minetest/UnzipService.java index ac9116994..6356dff19 100644 --- a/build/android/app/src/main/java/net/minetest/minetest/UnzipService.java +++ b/build/android/app/src/main/java/net/minetest/minetest/UnzipService.java @@ -28,11 +28,10 @@ import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Environment; -import android.util.Log; +import android.widget.Toast; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -44,9 +43,12 @@ public class UnzipService extends IntentService { public static final String ACTION_UPDATE = "net.minetest.minetest.UPDATE"; public static final String ACTION_PROGRESS = "net.minetest.minetest.PROGRESS"; public static final String EXTRA_KEY_IN_FILE = "file"; + public static final int SUCCESS = -1; + public static final int FAILURE = -2; private static final String TAG = "UnzipService"; private final int id = 1; private NotificationManager mNotifyManager; + private boolean isSuccess = true; public UnzipService() { super("net.minetest.minetest.UnzipService"); @@ -120,10 +122,9 @@ public class UnzipService extends IntentService { } zipFile.delete(); } - } catch (FileNotFoundException e) { - Log.e(TAG, e.getLocalizedMessage()); } catch (IOException e) { - Log.e(TAG, e.getLocalizedMessage()); + isSuccess = false; + Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); } } @@ -139,7 +140,7 @@ public class UnzipService extends IntentService { ZipFile zipSize = new ZipFile(zip); size += zipSize.size(); } catch (IOException e) { - Log.e(TAG, e.getLocalizedMessage()); + Toast.makeText(this, e.getLocalizedMessage(), Toast.LENGTH_LONG).show(); } return size; } @@ -148,6 +149,6 @@ public class UnzipService extends IntentService { public void onDestroy() { super.onDestroy(); mNotifyManager.cancel(id); - publishProgress(-1); + publishProgress(isSuccess ? SUCCESS : FAILURE); } } diff --git a/build/android/native/build.gradle b/build/android/native/build.gradle index f06e4e3f0..cbd50db6a 100644 --- a/build/android/native/build.gradle +++ b/build/android/native/build.gradle @@ -4,7 +4,7 @@ import org.ajoberstar.grgit.Grgit android { compileSdkVersion 29 buildToolsVersion '29.0.3' - ndkVersion '21.0.6113669' + ndkVersion '21.1.6352462' defaultConfig { minSdkVersion 16 targetSdkVersion 29 -- cgit v1.2.3 From 9d6e7e48d6fb1daff8fedcb2f111164bef61f1e7 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 22 May 2020 14:17:03 +0200 Subject: Implement spawning particles with node texture appearance --- build/android/native/jni/Android.mk | 1 + doc/lua_api.txt | 30 ++++++++++++- src/client/particles.cpp | 75 ++++++++++++++++++++++++-------- src/client/particles.h | 4 +- src/network/clientpackethandler.cpp | 10 +++++ src/particles.cpp | 10 +++++ src/particles.h | 6 +++ src/script/lua_api/l_particles.cpp | 14 ++++++ src/script/lua_api/l_particles_local.cpp | 14 ++++++ src/server.cpp | 1 + 10 files changed, 145 insertions(+), 20 deletions(-) (limited to 'build/android/native') diff --git a/build/android/native/jni/Android.mk b/build/android/native/jni/Android.mk index a5cb099e6..140947e6a 100644 --- a/build/android/native/jni/Android.mk +++ b/build/android/native/jni/Android.mk @@ -164,6 +164,7 @@ LOCAL_SRC_FILES := \ ../../../src/noise.cpp \ ../../../src/objdef.cpp \ ../../../src/object_properties.cpp \ + ../../../src/particles.cpp \ ../../../src/pathfinder.cpp \ ../../../src/player.cpp \ ../../../src/porting.cpp \ diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 26061eccb..5b3f61c99 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -7835,6 +7835,8 @@ Used by `minetest.add_particle`. size = 1, -- Scales the visual size of the particle texture. + -- If `node` is set, size can be set to 0 to spawn a randomly-sized + -- particle (just like actual node dig particles). collisiondetection = false, -- If true collides with `walkable` nodes and, depending on the @@ -7853,6 +7855,7 @@ Used by `minetest.add_particle`. -- If true faces player using y axis only texture = "image.png", + -- The texture of the particle playername = "singleplayer", -- Optional, if specified spawns particle only on the player's client @@ -7863,6 +7866,17 @@ Used by `minetest.add_particle`. glow = 0 -- Optional, specify particle self-luminescence in darkness. -- Values 0-14. + + node = {name = "ignore", param2 = 0}, + -- Optional, if specified the particle will have the same appearance as + -- node dig particles for the given node. + -- `texture` and `animation` will be ignored if this is set. + + node_tile = 0, + -- Optional, only valid in combination with `node` + -- If set to a valid number 1-6, specifies the tile from which the + -- particle texture is picked. + -- Otherwise, the default behavior is used. (currently: any random tile) } @@ -7892,7 +7906,9 @@ Used by `minetest.add_particlespawner`. maxsize = 1, -- The particles' properties are random values between the min and max -- values. - -- pos, velocity, acceleration, expirationtime, size + -- applies to: pos, velocity, acceleration, expirationtime, size + -- If `node` is set, min and maxsize can be set to 0 to spawn + -- randomly-sized particles (just like actual node dig particles). collisiondetection = false, -- If true collide with `walkable` nodes and, depending on the @@ -7915,6 +7931,7 @@ Used by `minetest.add_particlespawner`. -- If true face player using y axis only texture = "image.png", + -- The texture of the particle playername = "singleplayer", -- Optional, if specified spawns particles only on the player's client @@ -7925,6 +7942,17 @@ Used by `minetest.add_particlespawner`. glow = 0 -- Optional, specify particle self-luminescence in darkness. -- Values 0-14. + + node = {name = "ignore", param2 = 0}, + -- Optional, if specified the particles will have the same appearance as + -- node dig particles for the given node. + -- `texture` and `animation` will be ignored if this is set. + + node_tile = 0, + -- Optional, only valid in combination with `node` + -- If set to a valid number 1-6, specifies the tile from which the + -- particle texture is picked. + -- Otherwise, the default behavior is used. (currently: any random tile) } `HTTPRequest` definition diff --git a/src/client/particles.cpp b/src/client/particles.cpp index c2e751b4f..c78a3e71a 100644 --- a/src/client/particles.cpp +++ b/src/client/particles.cpp @@ -304,18 +304,37 @@ void ParticleSpawner::spawnParticle(ClientEnvironment *env, float radius, } pp.expirationtime = random_f32(p.minexptime, p.maxexptime); - pp.size = random_f32(p.minsize, p.maxsize); - p.copyCommon(pp); + video::ITexture *texture; + v2f texpos, texsize; + video::SColor color(0xFFFFFFFF); + + if (p.node.getContent() != CONTENT_IGNORE) { + const ContentFeatures &f = + m_particlemanager->m_env->getGameDef()->ndef()->get(p.node); + if (!ParticleManager::getNodeParticleParams(p.node, f, pp, &texture, + texpos, texsize, &color, p.node_tile)) + return; + } else { + texture = m_texture; + texpos = v2f(0.0f, 0.0f); + texsize = v2f(1.0f, 1.0f); + } + + // Allow keeping default random size + if (p.maxsize > 0.0f) + pp.size = random_f32(p.minsize, p.maxsize); + m_particlemanager->addParticle(new Particle( m_gamedef, m_player, env, pp, - m_texture, - v2f(0.0, 0.0), - v2f(1.0, 1.0) + texture, + texpos, + texsize, + color )); } @@ -460,17 +479,35 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client, break; } case CE_SPAWN_PARTICLE: { - const ParticleParameters &p = *event->spawn_particle; - video::ITexture *texture = - client->tsrc()->getTextureForMesh(p.texture); + ParticleParameters &p = *event->spawn_particle; - Particle *toadd = new Particle(client, player, m_env, - p, - texture, - v2f(0.0, 0.0), - v2f(1.0, 1.0)); + video::ITexture *texture; + v2f texpos, texsize; + video::SColor color(0xFFFFFFFF); + + f32 oldsize = p.size; + + if (p.node.getContent() != CONTENT_IGNORE) { + const ContentFeatures &f = m_env->getGameDef()->ndef()->get(p.node); + if (!getNodeParticleParams(p.node, f, p, &texture, texpos, + texsize, &color, p.node_tile)) + texture = nullptr; + } else { + texture = client->tsrc()->getTextureForMesh(p.texture); + texpos = v2f(0.0f, 0.0f); + texsize = v2f(1.0f, 1.0f); + } + + // Allow keeping default random size + if (oldsize > 0.0f) + p.size = oldsize; - addParticle(toadd); + if (texture) { + Particle *toadd = new Particle(client, player, m_env, + p, texture, texpos, texsize, color); + + addParticle(toadd); + } delete event->spawn_particle; break; @@ -480,15 +517,19 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client, } bool ParticleManager::getNodeParticleParams(const MapNode &n, - const ContentFeatures &f, ParticleParameters &p, - video::ITexture **texture, v2f &texpos, v2f &texsize, video::SColor *color) + const ContentFeatures &f, ParticleParameters &p, video::ITexture **texture, + v2f &texpos, v2f &texsize, video::SColor *color, u8 tilenum) { // No particles for "airlike" nodes if (f.drawtype == NDT_AIRLIKE) return false; // Texture - u8 texid = rand() % 6; + u8 texid; + if (tilenum > 0 && tilenum <= 6) + texid = tilenum - 1; + else + texid = rand() % 6; const TileLayer &tile = f.tiles[texid].layers[0]; p.animation.type = TAT_NONE; diff --git a/src/client/particles.h b/src/client/particles.h index 7dda0e1b1..2011f0262 100644 --- a/src/client/particles.h +++ b/src/client/particles.h @@ -42,7 +42,7 @@ class Particle : public scene::ISceneNode video::ITexture *texture, v2f texpos, v2f texsize, - video::SColor color = video::SColor(0xFFFFFFFF) + video::SColor color ); ~Particle() = default; @@ -171,7 +171,7 @@ public: protected: static bool getNodeParticleParams(const MapNode &n, const ContentFeatures &f, ParticleParameters &p, video::ITexture **texture, v2f &texpos, - v2f &texsize, video::SColor *color); + v2f &texsize, video::SColor *color, u8 tilenum = 0); void addParticle(Particle* toadd); diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 054e60c3c..e000acc92 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1003,6 +1003,16 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) p.glow = readU8(is); p.object_collision = readU8(is); + // This is kinda awful + do { + u16 tmp_param0 = readU16(is); + if (is.eof()) + break; + p.node.param0 = tmp_param0; + p.node.param2 = readU8(is); + p.node_tile = readU8(is); + } while (0); + auto event = new ClientEvent(); event->type = CE_ADD_PARTICLESPAWNER; event->add_particlespawner.p = new ParticleSpawnerParameters(p); diff --git a/src/particles.cpp b/src/particles.cpp index 711d189f6..fd81238dc 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -34,6 +34,9 @@ void ParticleParameters::serialize(std::ostream &os, u16 protocol_ver) const animation.serialize(os, 6); /* NOT the protocol ver */ writeU8(os, glow); writeU8(os, object_collision); + writeU16(os, node.param0); + writeU8(os, node.param2); + writeU8(os, node_tile); } void ParticleParameters::deSerialize(std::istream &is, u16 protocol_ver) @@ -50,4 +53,11 @@ void ParticleParameters::deSerialize(std::istream &is, u16 protocol_ver) animation.deSerialize(is, 6); /* NOT the protocol ver */ glow = readU8(is); object_collision = readU8(is); + // This is kinda awful + u16 tmp_param0 = readU16(is); + if (is.eof()) + return; + node.param0 = tmp_param0; + node.param2 = readU8(is); + node_tile = readU8(is); } diff --git a/src/particles.h b/src/particles.h index 659c1249f..6f518b771 100644 --- a/src/particles.h +++ b/src/particles.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "irrlichttypes_bloated.h" #include "tileanimation.h" +#include "mapnode.h" // This file defines the particle-related structures that both the server and // client need. The ParticleManager and rendering is in client/particles.h @@ -34,9 +35,12 @@ struct CommonParticleParams { std::string texture; struct TileAnimationParams animation; u8 glow = 0; + MapNode node; + u8 node_tile = 0; CommonParticleParams() { animation.type = TAT_NONE; + node.setContent(CONTENT_IGNORE); } /* This helper is useful for copying params from @@ -49,6 +53,8 @@ struct CommonParticleParams { to.texture = texture; to.animation = animation; to.glow = glow; + to.node = node; + to.node_tile = node_tile; } }; diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp index 7680aa17b..a51c4fe20 100644 --- a/src/script/lua_api/l_particles.cpp +++ b/src/script/lua_api/l_particles.cpp @@ -111,6 +111,13 @@ int ModApiParticles::l_add_particle(lua_State *L) p.texture = getstringfield_default(L, 1, "texture", p.texture); p.glow = getintfield_default(L, 1, "glow", p.glow); + lua_getfield(L, 1, "node"); + if (lua_istable(L, -1)) + p.node = readnode(L, -1, getGameDef(L)->ndef()); + lua_pop(L, 1); + + p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile); + playername = getstringfield_default(L, 1, "playername", ""); } @@ -231,6 +238,13 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) p.texture = getstringfield_default(L, 1, "texture", p.texture); playername = getstringfield_default(L, 1, "playername", ""); p.glow = getintfield_default(L, 1, "glow", p.glow); + + lua_getfield(L, 1, "node"); + if (lua_istable(L, -1)) + p.node = readnode(L, -1, getGameDef(L)->ndef()); + lua_pop(L, 1); + + p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile); } u32 id = getServer(L)->addParticleSpawner(p, attached, playername); diff --git a/src/script/lua_api/l_particles_local.cpp b/src/script/lua_api/l_particles_local.cpp index 9595b2fab..cc68b13a5 100644 --- a/src/script/lua_api/l_particles_local.cpp +++ b/src/script/lua_api/l_particles_local.cpp @@ -67,6 +67,13 @@ int ModApiParticlesLocal::l_add_particle(lua_State *L) p.texture = getstringfield_default(L, 1, "texture", p.texture); p.glow = getintfield_default(L, 1, "glow", p.glow); + lua_getfield(L, 1, "node"); + if (lua_istable(L, -1)) + p.node = readnode(L, -1, getGameDef(L)->ndef()); + lua_pop(L, 1); + + p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile); + ClientEvent *event = new ClientEvent(); event->type = CE_SPAWN_PARTICLE; event->spawn_particle = new ParticleParameters(p); @@ -134,6 +141,13 @@ int ModApiParticlesLocal::l_add_particlespawner(lua_State *L) p.texture = getstringfield_default(L, 1, "texture", p.texture); p.glow = getintfield_default(L, 1, "glow", p.glow); + lua_getfield(L, 1, "node"); + if (lua_istable(L, -1)) + p.node = readnode(L, -1, getGameDef(L)->ndef()); + lua_pop(L, 1); + + p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile); + u64 id = getClient(L)->getParticleManager()->generateSpawnerId(); auto event = new ClientEvent(); diff --git a/src/server.cpp b/src/server.cpp index 68b0131d4..d6e545498 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1577,6 +1577,7 @@ void Server::SendAddParticleSpawner(session_t peer_id, u16 protocol_version, pkt.putRawString(os.str()); } pkt << p.glow << p.object_collision; + pkt << p.node.param0 << p.node.param2 << p.node_tile; Send(&pkt); } -- cgit v1.2.3