Post your modding questions here

Locked
afeys
Member
Posts: 17
Joined: Thu Mar 26, 2015 08:55

Re: Post your modding questions here

by afeys » Post

@Don @Ferk

Thanks for the info.
I've now solved the chest problem: after placing the schematic in my world, I lookup all chests in the building and replace them by default:chest again. And then fill them with items (to fill them I use a piece of code I found in another mod: the villages mod by Sokomine I think).

User avatar
Ferk
Member
Posts: 337
Joined: Tue Aug 18, 2015 17:18
GitHub: Ferk

Re: Post your modding questions here

by Ferk » Post

That sounds like a cool mod.
blocks which decay if you step on them
The main problem with using ABMs to detect a player touching a node (other than being a lousy workaround for something that should be done in the engine) is that an ABM minimum interval is 1 second. So it's not very good for things that need a fast reaction since the player won't normally spend 1 second waiting in the node for the handler to kick in. But maybe for your usecase this would be fine. You might have to add an additional delay in case the player stepped the same instant the ABM activated, though.
a castle which gets randomly (sort of) generated by combining several pre-built building-part schematics to build either a small or a medium castle
That's very similar to what my subgame does. Maybe you can have a look at it, perhaps it helps. But most of dungeon_rooms is very specific to my usecase.
{ ☠ Dungeontest ☠ , ᗧ••myarcade•• }

afeys
Member
Posts: 17
Joined: Thu Mar 26, 2015 08:55

Re: Post your modding questions here

by afeys » Post

Ferk wrote: That's very similar to what my subgame does. Maybe you can have a look at it, perhaps it helps. But most of dungeon_rooms is very specific to my usecase.
Wow... just looked at your mod. looks very impressive.

User avatar
stu
Member
Posts: 923
Joined: Sat Feb 02, 2013 02:51
GitHub: stujones11
Location: United Kingdom

Re: Post your modding questions here

by stu » Post

Ferk wrote: The main problem with using ABMs to detect a player touching a node (other than being a lousy workaround for something that should be done in the engine) is that an ABM minimum interval is 1 second. So it's not very good for things that need a fast reaction since the player won't normally spend 1 second waiting in the node for the handler to kick in. But maybe for your usecase this would be fine. You might have to add an additional delay in case the player stepped the same instant the ABM activated, though
I doubt very much that stepping on/touching nodes will ever be handled by the engine, it would add way too much overhead, although I could be wrong there.

I suggest you take a look at how the mesecons pressure plates or player detectors work as those are reasonably responsive and iirc they do not rely on ABMs

User avatar
Napiophelios
Member
Posts: 1019
Joined: Mon Jul 07, 2014 01:14
GitHub: Napiophelios
IRC: Nappi
In-game: Nappi

Re: Post your modding questions here

by Napiophelios » Post

Ferk wrote:That sounds like a cool mod.
blocks which decay if you step on them
The main problem with using ABMs to detect a player touching a node (other than being a lousy workaround for something that should be done in the engine) is that an ABM minimum interval is 1 second. So it's not very good for things that need a fast reaction since the player won't normally spend 1 second waiting in the node for the handler to kick in. But maybe for your usecase this would be fine. You might have to add an additional delay in case the player stepped the same instant the ABM activated, though.
Pyramids by BlockMen uses similar traps.

But Maze by Echo uses "close stones" that seem much faster to react to players position and spring the traps.

Code: Select all

local maze_closer = {} -- list of all closer stones

-- closer stone definition
minetest.register_node("maze:closer", {
	tile_images = {"default_cobble.png"},
	inventory_image = minetest.inventorycube("default_cobble.png"),
	dug_item = '',
	material = { diggability = "not"},
	description = "Closestone",
})

-- detect player walk over closer stone (abm isn't fast enough)
minetest.register_globalstep(function(dtime)
	local players  = minetest.get_connected_players()
	for i,player in ipairs(players) do
		-- print(i.." "..player:get_player_name())
		for i, pos in ipairs(maze_closer) do
			local player_pos = player:getpos()
			local dist = math.sqrt( ((pos.x - player_pos.x) * (pos.x - player_pos.x)) +  ((pos.y - (player_pos.y - 0.5)) * (pos.y - (player_pos.y - 0.5))) +  ((pos.z - player_pos.z) * (pos.z - player_pos.z)) )
			if dist<3 then -- 2.2 would be enough, just make sure
				local meta = minetest.env:get_meta(pos)
				if dist<0.5 then
					meta:set_string("trap", "triggered")
				elseif dist > 1 then -- 0.71 would be enough, at least one node away
					if meta:get_string("trap") == "triggered" then
						meta:set_string("trap", "")
						minetest.env:add_node(pos,{name="default:cobble"})
						minetest.env:add_node({x = pos.x, y = pos.y + 1, z = pos.z},{name="default:cobble"})
						minetest.env:add_node({x = pos.x, y = pos.y + 2, z = pos.z},{name="default:cobble"})
					end
				end
			end
		end
	end

end)

-- create list of all closer stones (walk over detection now in globalstep, because abm isn't called often enough
minetest.register_abm(
	{nodenames = {"maze:closer"},
	interval = 1,
	chance = 1,
	action = function(pos, node, active_object_count, active_object_count_wider)
		local found = false
		for i, closer_pos in ipairs(maze_closer) do
			if closer_pos.x == pos.x and closer_pos.y == pos.y and closer_pos.z == pos.z then
				found = true
			end
		end
		if not found then
			table.insert(maze_closer, pos)
		end
	end,
})

User avatar
Ferk
Member
Posts: 337
Joined: Tue Aug 18, 2015 17:18
GitHub: Ferk

Re: Post your modding questions here

by Ferk » Post

It's faster because it uses globalstep. But that's also very hacky, and it doesn't look like he ever removes the node from the maze_closer table.. and you still have both an ABM and a globalstep handler running.

globalstep gets called every I think 0.05 seconds or something, if you don't keep track of the dtime (which it doesn't look like that code does) you are killing the CPU with that. Please correct me if I'm wrong.

If you don't have too many nodes to check it's probably more efficient to use timers, I guess timers get unloaded by the engine and handled more efficiently since the logic is all coded in C++. Note however that timers also won't get saved in mts schematics.

And all these approaches are workarounds, I still think it would be way better to have a handler on collision from the engine.
{ ☠ Dungeontest ☠ , ᗧ••myarcade•• }

User avatar
Ferk
Member
Posts: 337
Joined: Tue Aug 18, 2015 17:18
GitHub: Ferk

Re: Post your modding questions here

by Ferk » Post

stu wrote:I doubt very much that stepping on/touching nodes will ever be handled by the engine, it would add way too much overhead, although I could be wrong there.
Doesn't the engine already handle that? I mean.. how does it know a player can't go forward if there's a wall in front? or how does it know you are touching fire and should get damaged? I guess the server checks for collisions.
Or do you mean that that's client side? Even the damage_per_second?

Perhaps the problem is that the lua api is on a different, higher, level. Maybe some structural problem doesn't let them expose the collision logic to lua or they can't access the node definitions table. But I don't think the problem is overhead for checking the collisions.
stu wrote:I suggest you take a look at how the mesecons pressure plates or player detectors work as those are reasonably responsive and iirc they do not rely on ABMs
I had already done that, they use timers. Just a different way to apply the same approach used with ABMs. It's doable, just not very efficient.
afeys wrote:Wow... just looked at your mod. looks very impressive.
Thank you! :)
{ ☠ Dungeontest ☠ , ᗧ••myarcade•• }

User avatar
Don
Member
Posts: 1643
Joined: Sat May 17, 2014 18:40
GitHub: DonBatman
IRC: Batman
In-game: Batman

Re: Post your modding questions here

by Don » Post

Doesn't the engine already handle that? I mean.. how does it know a player can't go forward if there's a wall in front? or how does it know you are touching fire and should get damaged? I guess the server checks for collisions.
Or do you mean that that's client side? Even the damage_per_second?
I believe you are referring to collision.cpp.
Many of my mods are now a part of Minetest-mods. A place where you know they are maintained!

A list of my mods can be found here

User avatar
Ben
Member
Posts: 160
Joined: Tue Mar 31, 2015 20:09

Re: Post your modding questions here

by Ben » Post

Ferk wrote:It's faster because it uses globalstep. But that's also very hacky, and it doesn't look like he ever removes the node from the maze_closer table.. and you still have both an ABM and a globalstep handler running.
I'm guessing you could use an on_destruct handler (or whatever it's called) to remove nodes from maze_closer. Other than that, you'd never want to remove nodes from that table – it's supposed to be all the closers in the world. For that use case, though, the ABM is much too agressive. Every few seconds, with less than certain probability, should get you just as far.

I've done that in a mod, but I also had to make sure the surrounding nodes around my special node were still there. Otherwise, nowadays, I'd try handling on_place and on_destroy, and saving the maze_closer table to disk.
Ferk wrote:globalstep gets called every I think 0.05 seconds or something, if you don't keep track of the dtime (which it doesn't look like that code does) you are killing the CPU with that. Please correct me if I'm wrong.
Wasn't it every 0.1 seconds? And in my experience, CPU is "free" nowadays. Or at least you should profile first, optimize later. I once found that a loop I was worried over took about 100 microseconds, and stopped worrying ;-)

(One tip to save CPU time: don't compare the distance to a threshold, compare the square of the distance to the square of the threshold. Saves you a math.sqrt call. But then agan, free nowadays.)

(Another tip: don't use maze_closer as a list and then iterate with ipairs to find a node with a given position, use it as a map / directory / hash and test against maze_closer["x.y.z"]. Use pairs if you do need to iterate. Yes, I understand it's someone else's code in this example, but this irked me, and I'd like to throw this out there.)
Ferk wrote:…And all these approaches are workarounds, I still think it would be way better to have a handler on collision from the engine.
For actual collisions as in "standing on" or "standing in", I've been iterating over all players and testing get_node() at the relevant positions. This probably won't work for "pushing against" or "standing near", but it seems to work. Or am I doing it wrong?

User avatar
Ferk
Member
Posts: 337
Joined: Tue Aug 18, 2015 17:18
GitHub: Ferk

Re: Post your modding questions here

by Ferk » Post

@Ben you are correct, it's 0.1
About the distance calculation, perhaps the best is to use vector.distance(p1, p2)

We have a very convenient API in Minetest for operating with vectors, it's a shame most mods don't use it.
For actual collisions as in "standing on" or "standing in", I've been iterating over all players and testing get_node() at the relevant positions. This probably won't work for "pushing against" or "standing near", but it seems to work. Or am I doing it wrong?
That's what I'm doing as well for a pacman mod I'm working on. Seems to work fine for collecting the pellets. The only problem is that sometimes there are rounding issues and some pellets were getting missed so I actually have to check 2 positions instead of 1. I tried minetest.find_node_near but I have to either do a get_node anyway or do it a second time for the other type of "touchable" nodes, so I decided against it. Also even radius 1 was too big, probably get_node is faster.
in my experience, CPU is "free" nowadays
My i7 processor roars like a tiger when playing pacman. In singleplayer. I have yet to test it on a server.
Last edited by Ferk on Fri Oct 23, 2015 20:51, edited 1 time in total.
{ ☠ Dungeontest ☠ , ᗧ••myarcade•• }

User avatar
Ben
Member
Posts: 160
Joined: Tue Mar 31, 2015 20:09

Re: Post your modding questions here

by Ben » Post

Ferk wrote: About the distance calculation, perhaps the best is to use vector.distance(p1, p2)
I just looked up vector.distance: it's still implemented in Lua, and calls math.hypot twice. I've got a mind to make a pull request for vector.distance2 or similar. But that would be premature optimization ;-P
Ferk wrote:
Ben wrote:in my experience, CPU is "free" nowadays
My i7 processor roars like a tiger when playing pacman
Yeah, I should have qualified my remark a bit: I code websites for a living, where anything done in-process is practically invisible when compared to I/O :-P

User avatar
stu
Member
Posts: 923
Joined: Sat Feb 02, 2013 02:51
GitHub: stujones11
Location: United Kingdom

Re: Post your modding questions here

by stu » Post

Ferk wrote:Doesn't the engine already handle that? I mean.. how does it know a player can't go forward if there's a wall in front? or how does it know you are touching fire and should get damaged? I guess the server checks for collisions.
Or do you mean that that's client side? Even the damage_per_second?

Perhaps the problem is that the lua api is on a different, higher, level. Maybe some structural problem doesn't let them expose the collision logic to lua or they can't access the node definitions table. But I don't think the problem is overhead for checking the collisions.
Collision detection is indeed client side, that's exactly how hacked clients can get fly/no-clip on servers. Maybe someday this sort of thing will be possible with client-side modding, meanwhile the polling approach (however you trigger it) is really the only way you can do it

User avatar
Ferk
Member
Posts: 337
Joined: Tue Aug 18, 2015 17:18
GitHub: Ferk

Re: Post your modding questions here

by Ferk » Post

stu wrote:Collision detection is indeed client side, that's exactly how hacked clients can get fly/no-clip on servers. Maybe someday this sort of thing will be possible with client-side modding
I see, thanks, I understand now. I thought Minetest already was preventing cheating at that level.

Personally, I can accept giving up on cheat prevention on some levels. I think it's a trade-off, I'd rather have a fun game with many possibilities powered by client-side algorithms than a limited game full of bugs caused by the lag because of being afraid of the players cheating. I don't think Minetest is intended for any sort of professional cheat-protected tournament anyway. So I'd be happy to use client side APIs when available.
meanwhile the polling approach (however you trigger it) is really the only way you can do it
If this is really what everyone is using and / or people think it's worth it to do it in the server rather than the client, then maybe it would make sense to actually have either a "standard" lua library (or mod) to do it that can be peer reviewed and improved, or actually added to the engine as a server side check that only runs the polling whenever it makes sense. I guess there are ways in which this could be further optimized, even if it wasn't done using the client-side physics engine. Perhaps having a centralized system for it would help, so that we only iterate over the list of players once.
Last edited by Ferk on Sat Oct 24, 2015 13:24, edited 1 time in total.
{ ☠ Dungeontest ☠ , ᗧ••myarcade•• }

User avatar
stu
Member
Posts: 923
Joined: Sat Feb 02, 2013 02:51
GitHub: stujones11
Location: United Kingdom

Re: Post your modding questions here

by stu » Post

Ferk wrote:I see, thanks, I understand now. I thought Minetest already was preventing cheating at that level.

Personally, I can accept giving up on cheat prevention on some levels. I think it's a trade-off, I'd rather have a fun game with many possibilities powered by client-side algorithms than a limited game full of bugs caused by the lag because of being afraid of the players cheating. I don't think Minetest is intended for any sort of professional cheat-protected tournament anyway. So I'd be happy to use client side APIs when available.
Yes, of course there are anti-cheat mechanisms you can enable but I don't think that cheating is really that big of a problem. This is pretty much how all games of this nature work and it's just down to good server moderation to remove/ban any cheaters.

One possibility for your pacman game would be make it so that you have to dig the pips in order to move, not ideal I admit though it would save you a lot of problems.

User avatar
Don
Member
Posts: 1643
Joined: Sat May 17, 2014 18:40
GitHub: DonBatman
IRC: Batman
In-game: Batman

Re: Post your modding questions here

by Don » Post

We don't want to dig the pips. We want it like the original where you walk past it and it gets eaten.
Many of my mods are now a part of Minetest-mods. A place where you know they are maintained!

A list of my mods can be found here

User avatar
rubenwardy
Moderator
Posts: 6281
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy
Location: United Kingdom
Contact:

Re: Post your modding questions here

by rubenwardy » Post

Don wrote:We don't want to dig the pips. We want it like the original where you walk past it and it gets eaten.
I scrolled back a bit and couldn't find any context for this, other than it's pacman.

Couldn't you just modify the pick up code from PilzAdam's mod? So when you run over a pip entity, it is sucked up.

User avatar
Don
Member
Posts: 1643
Joined: Sat May 17, 2014 18:40
GitHub: DonBatman
IRC: Batman
In-game: Batman

Re: Post your modding questions here

by Don » Post

rubenwardy wrote:
Don wrote:We don't want to dig the pips. We want it like the original where you walk past it and it gets eaten.
I scrolled back a bit and couldn't find any context for this, other than it's pacman.

Couldn't you just modify the pick up code from PilzAdam's mod? So when you run over a pip entity, it is sucked up.
Look upa few posts to stu. His last paragraph.

The pips are nodes. The pacman pellets. Ferk has them working good but would work better if there was an on_collision function.
Many of my mods are now a part of Minetest-mods. A place where you know they are maintained!

A list of my mods can be found here

User avatar
Ferk
Member
Posts: 337
Joined: Tue Aug 18, 2015 17:18
GitHub: Ferk

Re: Post your modding questions here

by Ferk » Post

Yes, we are working together on the pacman mod.
I just checked PlizAdam's mod (I guess this one: https://github.com/PilzAdam/item_drop )

He uses a globalstep, along with get_objects_inside_radius. The pellets are nodes not object. If they were objects it might not work that well since there are more than 200 of them and they will probably constantly get loaded/unloaded.

The node "equivalent" function find_node_near has other problems, I mentioned that some comments above. It only returns positions so I ahve to either call it multiple times (once for each type of item to collect.. like the powerup or the fruits) or I'll have to do a get_node anyway for each of the nodes it finds.
{ ☠ Dungeontest ☠ , ᗧ••myarcade•• }

User avatar
paramat
Developer
Posts: 3691
Joined: Sun Oct 28, 2012 00:05
GitHub: paramat
IRC: paramat
Location: UK

Re: Post your modding questions here

by paramat » Post

My trail mod has code for changing nodes walked on, it's not very lightweight though, but reasonable https://github.com/paramat/trail

User avatar
stu
Member
Posts: 923
Joined: Sat Feb 02, 2013 02:51
GitHub: stujones11
Location: United Kingdom

Re: Post your modding questions here

by stu » Post

Don wrote:We don't want to dig the pips. We want it like the original where you walk past it and it gets eaten.
I like the idea of a pacman mod so I thought I would give something a quick try.

This idea uses the lua voxel manipulator so the maze position must be known in advance (pmin, pmax)

Code: Select all

local timer = 0

minetest.register_node("pacman:pip", {
	description = "Pacman Pip",
	tiles = {"pacman_pip.png"},
	walkable = false,
	on_collision = function(pos)
		minetest.remove_node(pos)
	end,
})

minetest.register_globalstep(function(dtime)
	timer = timer + dtime
	if timer > 0.1 then
		local pmin = {x=-20, y=0, z=-20}
		local pmax = {x=20, y=0, z=20}
		local vm = VoxelManip(pmin, pmax)
		for _,player in ipairs(minetest.get_connected_players()) do
			local pos = player:getpos()
			local node = vm:get_node_at(pos)
			local ref = minetest.registered_nodes[node.name]
			if type(ref.on_collision) == "function" then
				ref.on_collision(vector.round(pos))
			end
		end
		timer = 0
	end
end)
In this example I have given the nodes an on_collision callback but the removal could also be done directly using the vm.
I have no idea how well this would perform on a public server but it seems to work ok in singleplayer, even on my crappy old pc :/

Building on this idea, I guess you could do away with the vm and simply use a pre-defined array of pip locations. This way you only need to check if a player's current position matches one of the known pip locations which I reckon you can safely do on every server step.

Code: Select all

pacman = {
	pips = {},
}

minetest.register_node("pacman:pip", {
	description = "Pacman Pip",
	tiles = {"pacman_pip.png"},
	walkable = false,
})

minetest.register_abm({
	nodenames = {"pacman:pip"},
	interval = 1.0,
	chance = 1,
	action = function(pos, node)
		local id = minetest.hash_node_position(pos)
		pacman.pips[id] = 1
	end,
})

minetest.register_globalstep(function(dtime)
	for _,player in ipairs(minetest.get_connected_players()) do
		local pos = vector.round(player:getpos())
		local id = minetest.hash_node_position(pos)
		if pacman.pips[id] then
			minetest.remove_node(pos)
			pacman.pips[id] = nil
		end
	end
end)

User avatar
Ferk
Member
Posts: 337
Joined: Tue Aug 18, 2015 17:18
GitHub: Ferk

Re: Post your modding questions here

by Ferk » Post

Isn't allocating a new vm each cycle too much if you just want to check one or two nodes per step? We actually have already a working pacman that works ok in singleplayer. it's just that the discussion about the on_collision has been dragged for a few days in this thread :P ..it didn't even start with pacman.
use a pre-defined array of pip locations. This way you only need to check if a player's current position matches one of the known pip locations which I reckon you can safely do on every server step
That's clever, it would probably be much faster. We still have to test the game in a remote server, though, maybe the current approach is already enough, but that would be an interesting alternative.

Btw, what if I kept the same voxelmanip around and reused it in the globalstep? Does the vm keep the list of nodes in memory so it wouldn't need to poll the map every time and work pretty much like the list of pips in your second idea? It would use some more memory but then it doesn't need an abm.

I'm now writing some api to keep a list of highscores. The idea is actually to make a modpack with different arcade games. Hopefully pacman would be the first of many.
{ ☠ Dungeontest ☠ , ᗧ••myarcade•• }

minetestcr
Member
Posts: 58
Joined: Fri Feb 13, 2015 21:31

Re: Post your modding questions here

by minetestcr » Post

Hello. How can I make a node that lays flat on the node face it is placed? like the ladder in the image:
http://pasteboard.co/1D4bL4Lm.png
Image
thanks!

User avatar
Don
Member
Posts: 1643
Joined: Sat May 17, 2014 18:40
GitHub: DonBatman
IRC: Batman
In-game: Batman

Re: Post your modding questions here

by Don » Post

minetestcr wrote:Hello. How can I make a node that lays flat on the node face it is placed? like the ladder in the image:
http://pasteboard.co/1D4bL4Lm.png
Image
thanks!
Add this to your node def

Code: Select all

on_place = minetest.rotate_node
Many of my mods are now a part of Minetest-mods. A place where you know they are maintained!

A list of my mods can be found here

minetestcr
Member
Posts: 58
Joined: Fri Feb 13, 2015 21:31

Re: Post your modding questions here

by minetestcr » Post

Don wrote: Add this to your node def

Code: Select all

on_place = minetest.rotate_node
thanks Don... I tried, but I'm doing something wrong, I added the code like this:

Code: Select all

	minetest.register_node("stj:laminaverde", {
	description = "lámina verde",
	tiles = {
		"paredverde.png",
		"paredverde.png",
		"paredverde.png",
		"paredverde.png",
		"paredverde.png",
		"paredverde.png"
	},
	drawtype = "nodebox",
	paramtype = "light",
	on_place = minetest.rotate_node,
	material = minetest.digprop_constanttime(1.0),
	groups = {snappy=3,cracky=3,oddly_breakable_by_hand=3,},
	node_box = {
		type = "fixed",
		fixed = {
			{-0.5, -0.5, 0.4375, 0.5, 0.5, 0.5}, -- NodeBox1
		}
	}
})
	}

User avatar
Don
Member
Posts: 1643
Joined: Sat May 17, 2014 18:40
GitHub: DonBatman
IRC: Batman
In-game: Batman

Re: Post your modding questions here

by Don » Post

You need paramtype2 set

Code: Select all

paramtype2 = "facedir",
Many of my mods are now a part of Minetest-mods. A place where you know they are maintained!

A list of my mods can be found here

Locked

Who is online

Users browsing this forum: No registered users and 2 guests