Add playerphysics and sprint

master
CasimirKaPazi 2022-08-14 15:24:21 +02:00
parent f7824aadec
commit d6b689ae81
9 changed files with 513 additions and 2 deletions

View File

@ -46,7 +46,7 @@ What not to add:
Voxelgarden should be (in that order):
a complete game >> easy to maintain >> compatible with minetest game
a complete game >> easy to maintain >> compatible with minetest game
License of source code:
@ -62,7 +62,7 @@ http://www.gnu.org/licenses/lgpl-2.1.html
For every mod applies the original license. See list below.
All other media is licenced under Creative Commons BY-SA license.
beds (LGPL), bones (LGPL), bucket (LGPL), conifer (LGPL), creative (LGPL), default (LGPL), doors (LGPL), dye (LGPL), game_commands(MIT), farming (LGPL), fire (LGPL), flowers (LGPL), footsteps (LGPL), hunger (LGPL), inventory\_plus (GPL), mobs (MIT), mobs\_flat (LGPL), physics (LGPL), player_api (LGPL), stairs (LGPL), stairsplus (zlib/libpng), walls (LGPL) wool (LGPL), zcg (LGPL), xpanes (LGPL)
beds (LGPL), bones (LGPL), bucket (LGPL), conifer (LGPL), creative (LGPL), default (LGPL), doors (LGPL), dye (LGPL), game_commands(MIT), farming (LGPL), fire (LGPL), flowers (LGPL), footsteps (LGPL), hunger (LGPL), inventory\_plus (GPL), mobs (MIT), mobs\_flat (LGPL), physics (LGPL), player_api (LGPL), playerphysics (MIT), sprint (CC0), stairs (LGPL), stairsplus (zlib/libpng), walls (LGPL) wool (LGPL), zcg (LGPL), xpanes (LGPL)
Mods equivalent to and mirroring Minetest Game:
binoculars (MIT), boats (MIT) (except burntime), carts (MIT), dungeon_loot (MIT), env_sounds (MIT), fireflies (MIT), map (MIT), screwdriver (LGPL) (except texture), tnt (MIT) (except textures), vessels (LGPL), weather (MIT)

View File

@ -39,6 +39,28 @@ function hunger.update_bar(player, full)
end
end
-- Allow mods to tell us that the player is active
function hunger.active(player)
if not player then return end
local name = player:get_player_name()
player_is_active[name] = true
end
function hunger.get(player)
if not player then return end
local meta = player:get_meta()
local full = meta:get_int("hunger")
return full
end
function hunger.set(player, full)
if not player then return end
local name = player:get_player_name()
local meta = player:get_meta()
hunger.update_bar(player, full)
meta:set_int("hunger", full)
end
-- no_hunger privilege
minetest.register_privilege("no_hunger", {
description = S("Player will feel no hunger."),

View File

@ -0,0 +1,123 @@
# Player Physics API.
Version: 1.0.1
This mod makes it possible for multiple mods to modify player physics (speed, jumping strength, gravity) without conflict.
## Introduction
### For players
Mods and games in Minetest can set physical attributes of players, such as speed and jump strength. For example, player speed could be set to 200%. But the way this works makes it difficult for multiple mods to *modify* physical attributes without leading to conflicts, problems and hilarious bugs, like speed that changes often to nonsense values.
The Player Physics API aims to resolve this conflict by providing a “common ground” for mods to work together in this regard.
This mod does nothing on its own, you will only need to install it as dependency of other mods.
When you browse for mods that somehow mess with player physics (namely: speed, jump strength or gravity) and want to use more than one of them, check out if they support the Player Physics API. If they don't, it's very likely these mods will break as soon you activate more than one of them, for example, if two mods try to set the player speed. If you found such a “hilarious bug”, please report it to the developers of the mods (or games) and point them to the Player Physics API.
Of course, not all mods need the Player Physics API. Mods that don't touch player physics at all won't need this mod.
The rest of this document is directed at developers.
### For developers
The function `set_physics_override` from the Minetest Lua API allows mod authors to override physical attributes of players, such as speed or jump strength.
This function works fine as long there is only one mod that sets a particular physical attribute at a time. However, as soon as at least two different mods (that do not know each other) try to change the same player physics attribute using only this function, there will be conflicts as each mod will undo the change of the other mod, as the function sets a raw value. A classic race condition occurs. This is the case because the mods fail to communicate with each other.
This mod solves the problem of conflicts. It bans the concept of “setting the raw value directly” and replaces it with the concept of factors that mods can add and remove for each attribute. The real physical player attribute will be the product of all active factors.
## Quick start
Let's say you have a mod `example` and want to double the speed of the player (i.e. multiply it by a factor of 2), but you also don't want to break other mods that might touch the speed.
Previously, you might have written something like this:
`player:set_physics_override({speed=2})`
However, your mod broke down as soon the mod `example2` came along, which wanted to increase the speed by 50%. In the real game, the player speed randomly switched from 50% and 200% which was a very annoying bug.
In your `example` mod, you can replace the code with this:
`playerphysics.add_physics_factor(player, "speed", "my_double_speed", 2)`
Where `"my_double_speed` is an unique ID for your speed factor.
Now your `example` mod is interoperable! And now, of course, the `example2` mod has to be updated in a similar fashion.
## Precondition
There is only one precondition to using this mod, but it is important:
Mods *MUST NOT* call `set_physics_override` directly for numerical values. Instead, to modify player physics, all mods that touch player physics have to use this API.
## Functions
### `playerphysics.add_physics_factor(player, attribute, id, value)`
Adds a factor for a player physic and updates the player physics immediately.
#### Parameters
* `player`: Player object
* `attribute`: Which of the physical attributes to change. Any of the numeric values of `set_physics_override` (e.g. `"speed"`, `"jump"`, `"gravity"`)
* `id`: Unique identifier for this factor. Identifiers are stored on a per-player per-attribute type basis
* `value`: The factor to add to the list of products
If a factor for the same player, attribute and `id` already existed, it will be overwritten.
### `playerphysics.remove_physics_factor(player, attribute, id)`
Removes the physics factor of the given ID and updates the player's physics.
#### Parameters
Same as in `playerphysics.add_physics_factor`, except there is no `value` argument.
## Examples
### Speed changes
Let's assume this mod is used by 3 different mods all trying to change the speed:
Potions, Exhaustion and Electrocution.
Here's what it could look like:
Potions mod:
```
playerphysics.add_physics_factor(player, "speed", "run_potion", 2)
```
Exhaustion mod:
```
playerphysics.add_physics_factor(player, "jump", "exhausted", 0.75)
```
Electrocution mod:
```
playerphysics.add_physics_factor(player, "jump", "shocked", 0.9)
```
When the 3 mods have done their change, the real player speed is simply the product of all factors, that is:
2 * 0.75 * 0.9 = 1.35
The final player speed is thus 135%.
### Speed changes, part 2
Let's take the example above.
Now if the Electrocution mod is done with shocking the player, it just needs to call:
```
playerphysics.remove_physics_factor(player, "jump", "shocked")
```
The effect is now gone, so the new player speed will be:
2 * 0.75 = 1.5
### Sleeping
To simulate sleeping by preventing all player movement, this can be done with this easy trick:
```
playerphysics.add_physics_factor(player, "speed", "sleeping", 0)
playerphysics.add_physics_factor(player, "jump", "sleeping", 0)
```
This works regardless of the other factors because 0 times anything equals 0.
## License
This mod is free software, released under the MIT License.

View File

@ -0,0 +1,45 @@
playerphysics = {}
local function calculate_attribute_product(player, attribute)
local a = minetest.deserialize(player:get_meta():get_string("playerphysics:physics"))
local product = 1
if a == nil or a[attribute] == nil then
return product
end
local factors = a[attribute]
if type(factors) == "table" then
for _, factor in pairs(factors) do
product = product * factor
end
end
return product
end
function playerphysics.add_physics_factor(player, attribute, id, value)
local meta = player:get_meta()
local a = minetest.deserialize(meta:get_string("playerphysics:physics"))
if a == nil then
a = { [attribute] = { [id] = value } }
elseif a[attribute] == nil then
a[attribute] = { [id] = value }
else
a[attribute][id] = value
end
meta:set_string("playerphysics:physics", minetest.serialize(a))
local raw_value = calculate_attribute_product(player, attribute)
player:set_physics_override({[attribute] = raw_value})
end
function playerphysics.remove_physics_factor(player, attribute, id)
local meta = player:get_meta()
local a = minetest.deserialize(meta:get_string("playerphysics:physics"))
if a == nil or a[attribute] == nil then
-- Nothing to remove
return
else
a[attribute][id] = nil
end
meta:set_string("playerphysics:physics", minetest.serialize(a))
local raw_value = calculate_attribute_product(player, attribute)
player:set_physics_override({[attribute] = raw_value})
end

View File

@ -0,0 +1,5 @@
name = playerphysics
description = This mod makes it possible for multiple mods to modify player physics (speed, jumping strength, gravity) without conflict.
release = 8397
author = Wuzzy
title = Player Physics API

121
mods/sprint/COPYING Normal file
View File

@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

17
mods/sprint/README.md Normal file
View File

@ -0,0 +1,17 @@
# Sprint Mod for MineClone 2
Forked from [sprint] by GunshipPenguin
## Description
Allows the player to sprint by pressing the “Use” key (default: E).
By default, sprinting will make the player travel 80% faster and
allow him/her to jump 10% higher.
Licence: CC0 (see COPYING file)
## Mod developer settings (`init.lua`)
### `sprint.SPEED`
How fast the player will move when sprinting as opposed to normal
movement speed. 1.0 represents normal speed so 1.5 would mean that a
sprinting player would travel 50% faster than a walking player and
2.4 would mean that a sprinting player would travel 140% faster than
a walking player.

176
mods/sprint/init.lua Normal file
View File

@ -0,0 +1,176 @@
--[[
Sprint mod for Minetest by GunshipPenguin
To the extent possible under law, the author(s)
have dedicated all copyright and related and neighboring rights
to this software to the public domain worldwide. This software is
distributed without any warranty.
]]
--Configuration variables, these are all explained in README.md
sprint = {}
sprint.SPEED = 1.2
local players = {}
-- Returns true if the player with the given name is sprinting, false if not.
-- Returns nil if player does not exist.
sprint.is_sprinting = function(playername)
if players[playername] then
return players[playername].sprinting
else
return nil
end
end
minetest.register_on_joinplayer(function(player)
local playerName = player:get_player_name()
players[playerName] = {
sprinting = false,
timeOut = 0,
shouldSprint = false,
lastPos = player:get_pos(),
sprintDistance = 0,
fov = 1.0
}
end)
minetest.register_on_leaveplayer(function(player)
local playerName = player:get_player_name()
players[playerName] = nil
end)
local function setSprinting(playerName, sprinting) --Sets the state of a player (0=stopped/moving, 1=sprinting)
local player = minetest.get_player_by_name(playerName)
if players[playerName] then
players[playerName].sprinting = sprinting
if sprinting == true then
players[playerName].fov = math.min(players[playerName].fov + 0.05, 1.2)
player:set_fov(players[playerName].fov, true, 0.15)
playerphysics.add_physics_factor(player, "speed", "sprint:sprint", sprint.SPEED)
elseif sprinting == false then
players[playerName].fov = math.max(players[playerName].fov - 0.05, 1.0)
player:set_fov(players[playerName].fov, true, 0.15)
playerphysics.remove_physics_factor(player, "speed", "sprint:sprint")
end
return true
end
return false
end
-- Given the param2 and paramtype2 of a node, returns the tile that is facing upwards
local function get_top_node_tile(param2, paramtype2)
if paramtype2 == "colorwallmounted" then
paramtype2 = "wallmounted"
param2 = param2 % 8
elseif paramtype2 == "colorfacedir" then
paramtype2 = "facedir"
param2 = param2 % 32
end
if paramtype2 == "wallmounted" then
if param2 == 0 then
return 2
elseif param2 == 1 then
return 1
else
return 5
end
elseif paramtype2 == "facedir" then
if param2 >= 0 and param2 <= 3 then
return 1
elseif param2 == 4 or param2 == 10 or param2 == 13 or param2 == 19 then
return 6
elseif param2 == 5 or param2 == 11 or param2 == 14 or param2 == 16 then
return 3
elseif param2 == 6 or param2 == 8 or param2 == 15 or param2 == 17 then
return 5
elseif param2 == 7 or param2 == 9 or param2 == 12 or param2 == 18 then
return 4
elseif param2 >= 20 and param2 <= 23 then
return 2
else
return 1
end
else
return 1
end
end
minetest.register_globalstep(function(dtime)
--Get the gametime
local gameTime = minetest.get_gametime()
--Loop through all connected players
for playerName,playerInfo in pairs(players) do
local player = minetest.get_player_by_name(playerName)
if player ~= nil then
local ctrl = player:get_player_control()
--Check if the player should be sprinting
if ctrl.aux1 and ctrl.up and not ctrl.sneak then
players[playerName]["shouldSprint"] = true
else
players[playerName]["shouldSprint"] = false
end
local playerPos = player:get_pos()
--If the player is sprinting, create particles behind and cause exhaustion
if playerInfo["sprinting"] == true and gameTime % 0.1 == 0 then
-- Exhaust player for sprinting
local lastPos = players[playerName].lastPos
local dist = vector.distance({x=lastPos.x, y=0, z=lastPos.z}, {x=playerPos.x, y=0, z=playerPos.z})
players[playerName].sprintDistance = players[playerName].sprintDistance + dist
if players[playerName].sprintDistance >= 1 then
local superficial = math.floor(players[playerName].sprintDistance)
local full = hunger.get(minetest.get_player_by_name(playerName))
- math.floor(superficial / 5)
if full < 0 then full = 0 end
hunger.set(minetest.get_player_by_name(playerName), full)
players[playerName].sprintDistance = players[playerName].sprintDistance - superficial
end
-- Sprint node particles
local playerNode = minetest.get_node({x=playerPos["x"], y=playerPos["y"]-1, z=playerPos["z"]})
local def = minetest.registered_nodes[playerNode.name]
if def and def.walkable then
minetest.add_particlespawner({
amount = math.random(1, 2),
time = 1,
minpos = {x=-0.5, y=0.1, z=-0.5},
maxpos = {x=0.5, y=0.1, z=0.5},
minvel = {x=0, y=5, z=0},
maxvel = {x=0, y=5, z=0},
minacc = {x=0, y=-13, z=0},
maxacc = {x=0, y=-13, z=0},
minexptime = 0.1,
maxexptime = 1,
minsize = 0.5,
maxsize = 1.5,
collisiondetection = true,
attached = player,
vertical = false,
node = playerNode,
node_tile = get_top_node_tile(playerNode.param2, def.paramtype2),
})
end
end
--Adjust player states
players[playerName].lastPos = playerPos
if players[playerName]["shouldSprint"] == true then --Stopped
local sprinting
-- Prevent sprinting if hungry
if hunger.get(minetest.get_player_by_name(playerName)) <= 2 then
sprinting = false
else
sprinting = true
end
setSprinting(playerName, sprinting)
elseif players[playerName]["shouldSprint"] == false then
setSprinting(playerName, false)
end
end
end
end)

2
mods/sprint/mod.conf Normal file
View File

@ -0,0 +1,2 @@
name = sprint
depends = playerphysics, hunger