2016-01-30 08:56:04 +01:00
|
|
|
|
|
|
|
--[[
|
|
|
|
|
2017-02-07 22:45:57 +01:00
|
|
|
Copyright 2016-2017 - Auke Kok <sofar@foo-projects.org>
|
2017-01-20 02:55:19 +01:00
|
|
|
Copyright 2017 - Elijah Duffy <theoctacian@gmail.com>
|
2017-05-05 09:04:35 +02:00
|
|
|
Copyright 2017 - sys4 <sys4@free.fr>
|
2016-01-30 08:56:04 +01:00
|
|
|
|
|
|
|
License:
|
2017-03-21 17:48:56 +01:00
|
|
|
- Code: MIT
|
|
|
|
- Models and textures: CC-BY-SA-3.0
|
2017-01-20 02:55:19 +01:00
|
|
|
Usage: /camera
|
2017-03-21 17:48:56 +01:00
|
|
|
Execute command to start recording. While recording:
|
|
|
|
- use up/down to accelerate/decelerate
|
|
|
|
- use jump to brake
|
|
|
|
- use crouch to stop recording
|
|
|
|
Use /camera play to play back the last recording. While playing back:
|
|
|
|
- use crouch to stop playing back
|
|
|
|
Use /camera play <name> to play a specific recording
|
|
|
|
Use /camera save <name> to save the last recording
|
|
|
|
- saved recordings exist through game restarts
|
|
|
|
Use /camera list to show all saved recording
|
2017-05-05 09:04:35 +02:00
|
|
|
Use /camera mode <0|2> to change the velocity behaviour
|
|
|
|
- 0: Velocity follow mouse (default),
|
|
|
|
- 2: Velocity locked to player's first look direction with released mouse
|
|
|
|
Use /camera look <nil|here|x,y,z>
|
|
|
|
- nil: remove looking target,
|
|
|
|
- here: set looking target to player position,
|
|
|
|
- x,y,z: Coords to look at
|
|
|
|
Use /camera speed <speed>
|
|
|
|
- 10 is default speed,
|
|
|
|
- > 10 decrease speed factor,
|
|
|
|
- < 10 increase speed factor
|
2016-01-30 08:56:04 +01:00
|
|
|
--]]
|
|
|
|
|
|
|
|
local recordings = {}
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- [function] Load recordings
|
2017-02-07 16:32:06 +01:00
|
|
|
local path = minetest.get_worldpath()
|
|
|
|
|
|
|
|
local function load()
|
2017-03-21 17:48:56 +01:00
|
|
|
local res = io.open(path.."/recordings.txt", "r")
|
|
|
|
if res then
|
|
|
|
res = minetest.deserialize(res:read("*all"))
|
|
|
|
if type(res) == "table" then
|
|
|
|
recordings = res
|
|
|
|
end
|
|
|
|
end
|
2017-02-07 16:32:06 +01:00
|
|
|
end
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- Call load
|
2017-02-07 16:32:06 +01:00
|
|
|
load()
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- [function] Save recordings
|
2017-02-07 16:32:06 +01:00
|
|
|
function save()
|
2017-03-21 17:48:56 +01:00
|
|
|
io.open(path.."/recordings.txt", "w"):write(minetest.serialize(recordings))
|
2017-02-07 16:32:06 +01:00
|
|
|
end
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- [function] Get recording list per-player for chat
|
2017-02-07 16:32:06 +01:00
|
|
|
function get_recordings(name)
|
2017-03-21 17:48:56 +01:00
|
|
|
local recs = recordings[name]
|
|
|
|
local list = ""
|
|
|
|
|
|
|
|
if recs then
|
|
|
|
for name, path in pairs(recs) do
|
|
|
|
list = list..name..", "
|
|
|
|
end
|
|
|
|
return list
|
|
|
|
else
|
|
|
|
return "You do not saved any recordings."
|
|
|
|
end
|
2017-02-07 16:32:06 +01:00
|
|
|
end
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- [event] On shutdown save recordings
|
2017-02-07 16:32:06 +01:00
|
|
|
minetest.register_on_shutdown(save)
|
|
|
|
|
|
|
|
-- Table for storing unsaved temporary recordings
|
|
|
|
local temp = {}
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- Camera definition
|
2016-01-30 08:56:04 +01:00
|
|
|
local camera = {
|
|
|
|
description = "Camera",
|
2017-01-20 02:55:19 +01:00
|
|
|
visual = "wielditem",
|
|
|
|
textures = {},
|
2016-01-30 08:56:04 +01:00
|
|
|
physical = false,
|
2017-01-20 02:55:19 +01:00
|
|
|
is_visible = false,
|
|
|
|
collide_with_objects = false,
|
|
|
|
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
|
|
|
physical = false,
|
|
|
|
visual = "cube",
|
2016-01-30 08:56:04 +01:00
|
|
|
driver = nil,
|
|
|
|
mode = 0,
|
|
|
|
velocity = {x=0, y=0, z=0},
|
|
|
|
old_pos = nil,
|
|
|
|
old_velocity = nil,
|
|
|
|
pre_stop_dir = nil,
|
|
|
|
MAX_V = 20,
|
|
|
|
init = function(self, player, mode)
|
|
|
|
self.driver = player
|
|
|
|
self.mode = mode
|
|
|
|
self.path = {}
|
|
|
|
end,
|
|
|
|
}
|
|
|
|
|
2017-05-05 09:04:35 +02:00
|
|
|
local player_look_dir = nil -- player look direction when starting record
|
|
|
|
local target_look_position = nil -- looking target
|
2017-05-03 22:27:25 +02:00
|
|
|
local speed_factor = 0.1 -- default speed factor
|
2017-05-05 09:04:35 +02:00
|
|
|
local rec_mode = 0 -- record mode
|
2017-07-18 03:02:15 +02:00
|
|
|
local rotate = false
|
|
|
|
local rotate_speed = 0
|
2017-01-20 02:55:19 +01:00
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- [event] On step
|
2016-01-30 08:56:04 +01:00
|
|
|
function camera:on_step(dtime)
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if not driver, remove object
|
2016-01-30 08:56:04 +01:00
|
|
|
if not self.driver then
|
|
|
|
self.object:remove()
|
|
|
|
return
|
|
|
|
end
|
2017-02-07 23:07:18 +01:00
|
|
|
|
2016-01-30 08:56:04 +01:00
|
|
|
local pos = self.object:getpos()
|
|
|
|
local vel = self.object:getvelocity()
|
|
|
|
local dir = self.driver:get_look_dir()
|
2017-07-18 03:02:15 +02:00
|
|
|
local cos_yaw, sin_yaw
|
2016-01-30 08:56:04 +01:00
|
|
|
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if record mode
|
2017-05-05 09:04:35 +02:00
|
|
|
if self.mode == 0 or self.mode == 2 then
|
2017-04-30 18:33:03 +02:00
|
|
|
-- Calculate pitch and yaw if target_look_position defined
|
|
|
|
if target_look_position then
|
|
|
|
local vec_pos = vector.subtract(target_look_position, pos)
|
|
|
|
|
|
|
|
-- Pitch
|
|
|
|
local opp = vec_pos.y
|
|
|
|
local adj = vec_pos.x
|
|
|
|
|
|
|
|
if math.abs(vec_pos.z) > math.abs(vec_pos.x) then
|
|
|
|
adj = vec_pos.z
|
|
|
|
end
|
|
|
|
|
2017-05-05 09:04:35 +02:00
|
|
|
self.driver:set_look_vertical(math.atan((opp*-1)/math.abs(adj)))
|
|
|
|
|
2017-04-30 18:33:03 +02:00
|
|
|
-- Yaw
|
|
|
|
opp = vec_pos.x
|
|
|
|
adj = vec_pos.z
|
|
|
|
|
2017-05-05 09:04:35 +02:00
|
|
|
local yaw = math.atan(opp/adj)
|
2017-04-30 18:33:03 +02:00
|
|
|
|
|
|
|
if math.abs(vec_pos.x) > math.abs(vec_pos.z) then
|
2017-05-05 09:04:35 +02:00
|
|
|
yaw = math.atan(adj/opp)
|
|
|
|
|
2017-04-30 18:33:03 +02:00
|
|
|
if adj < 0 and opp < 0 then
|
|
|
|
yaw = yaw + math.pi/2
|
|
|
|
end
|
|
|
|
|
|
|
|
if adj > 0 and opp > 0 then
|
|
|
|
yaw = yaw + math.pi + math.pi/2
|
|
|
|
end
|
|
|
|
|
|
|
|
if yaw < 0 then
|
|
|
|
if opp > 0 then
|
|
|
|
yaw = math.pi + math.pi/2 + yaw
|
|
|
|
else
|
|
|
|
yaw = math.pi/2 + yaw
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
else
|
|
|
|
if adj < 0 and opp < 0 then
|
|
|
|
yaw = yaw - math.pi
|
|
|
|
end
|
|
|
|
|
|
|
|
if adj > 0 and opp > 0 then
|
|
|
|
yaw = math.pi*2 - yaw
|
|
|
|
end
|
|
|
|
|
|
|
|
if yaw < 0 then
|
|
|
|
if opp > 0 then
|
|
|
|
yaw = math.pi - yaw
|
|
|
|
else
|
|
|
|
yaw = math.pi*2 - yaw
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-05-05 09:04:35 +02:00
|
|
|
self.driver:set_look_horizontal(yaw)
|
2017-07-18 03:02:15 +02:00
|
|
|
|
|
|
|
-- Make velocity to rotate camera
|
|
|
|
if rotate then
|
|
|
|
cos_yaw = math.cos(yaw)
|
|
|
|
sin_yaw = math.sin(yaw)
|
|
|
|
end
|
2017-04-30 18:33:03 +02:00
|
|
|
end
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- Update path
|
2016-01-30 08:56:04 +01:00
|
|
|
self.path[#self.path + 1] = {
|
|
|
|
pos = pos,
|
|
|
|
velocity = vel,
|
|
|
|
pitch = self.driver:get_look_pitch(),
|
|
|
|
yaw = self.driver:get_look_yaw()
|
|
|
|
}
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- Modify yaw and pitch to match driver (player)
|
2016-01-30 08:56:04 +01:00
|
|
|
self.object:set_look_pitch(self.driver:get_look_pitch())
|
|
|
|
self.object:set_look_yaw(self.driver:get_look_yaw())
|
2017-01-20 02:55:19 +01:00
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- Get controls
|
2016-01-30 08:56:04 +01:00
|
|
|
local ctrl = self.driver:get_player_control()
|
2017-02-07 23:07:18 +01:00
|
|
|
|
2017-03-21 17:48:56 +01:00
|
|
|
-- Initialize speed
|
2016-01-30 08:56:04 +01:00
|
|
|
local speed = vector.distance(vector.new(), vel)
|
2017-02-07 23:07:18 +01:00
|
|
|
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if up, accelerate forward
|
2016-01-30 08:56:04 +01:00
|
|
|
if ctrl.up then
|
2017-05-03 22:27:25 +02:00
|
|
|
speed = math.min(speed + speed_factor, 20)
|
2017-07-18 03:02:15 +02:00
|
|
|
if rotate then
|
|
|
|
rotate_speed = math.min(rotate_speed + speed_factor, 0.8)
|
|
|
|
end
|
2016-01-30 08:56:04 +01:00
|
|
|
end
|
2017-02-07 23:07:18 +01:00
|
|
|
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if down, accelerate backward
|
2016-01-30 08:56:04 +01:00
|
|
|
if ctrl.down then
|
2017-05-03 22:27:25 +02:00
|
|
|
speed = math.max(speed - speed_factor, -20)
|
2017-07-18 03:02:15 +02:00
|
|
|
if rotate then
|
|
|
|
rotate_speed = math.max(rotate_speed - speed_factor, -0.8)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- if left, rotate to left
|
|
|
|
if ctrl.left and target_look_position then
|
|
|
|
if rotate_speed == 0 and speed >= 0 then
|
|
|
|
rotate = true
|
|
|
|
rotate_speed = math.max(-speed, -0.8)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- if right, rotate to right
|
|
|
|
if ctrl.right and target_look_position then
|
|
|
|
if rotate_speed == 0 and speed >= 0 then
|
|
|
|
rotate = true
|
|
|
|
rotate_speed = math.min(speed, 0.8)
|
|
|
|
end
|
2016-01-30 08:56:04 +01:00
|
|
|
end
|
2017-02-07 23:07:18 +01:00
|
|
|
|
2017-07-18 03:02:15 +02:00
|
|
|
-- if aux1 (aka key 'e') then stop rotate
|
|
|
|
if ctrl.aux1 then
|
|
|
|
rotate = false
|
|
|
|
rotate_speed = 0
|
|
|
|
end
|
|
|
|
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if jump, brake
|
2016-01-30 08:56:04 +01:00
|
|
|
if ctrl.jump then
|
|
|
|
speed = math.max(speed * 0.9, 0.0)
|
2017-07-18 03:02:15 +02:00
|
|
|
if rotate then
|
|
|
|
rotate_speed = math.max(rotate_speed * 0.9, 0.0)
|
|
|
|
end
|
2016-01-30 08:56:04 +01:00
|
|
|
end
|
2017-02-07 23:07:18 +01:00
|
|
|
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if sneak, stop recording
|
2016-01-30 08:56:04 +01:00
|
|
|
if ctrl.sneak then
|
|
|
|
self.driver:set_detach()
|
|
|
|
minetest.chat_send_player(self.driver:get_player_name(), "Recorded stopped after " .. #self.path .. " points")
|
2017-02-07 16:32:06 +01:00
|
|
|
temp[self.driver:get_player_name()] = table.copy(self.path)
|
2016-01-30 08:56:04 +01:00
|
|
|
self.object:remove()
|
|
|
|
return
|
|
|
|
end
|
2017-02-07 23:07:18 +01:00
|
|
|
|
2017-03-21 17:48:56 +01:00
|
|
|
-- Set updated velocity
|
2017-05-05 09:04:35 +02:00
|
|
|
if self.mode == 0 then
|
|
|
|
self.object:setvelocity(vector.multiply(self.driver:get_look_dir(), speed))
|
|
|
|
elseif self.mode == 2 then
|
2017-07-18 03:02:15 +02:00
|
|
|
if rotate and cos_yaw and sin_yaw then
|
|
|
|
local velocity = { x = self.object:getvelocity().x+cos_yaw, y = 0, z = self.object:getvelocity().z+sin_yaw}
|
|
|
|
self.object:setvelocity(vector.multiply(velocity, rotate_speed))
|
|
|
|
else
|
|
|
|
self.object:setvelocity(vector.multiply(player_look_dir, speed))
|
|
|
|
end
|
2017-05-05 09:04:35 +02:00
|
|
|
end
|
2017-07-18 03:02:15 +02:00
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
elseif self.mode == 1 then -- elseif playback mode
|
|
|
|
-- Get controls
|
2016-01-30 08:56:04 +01:00
|
|
|
local ctrl = self.driver:get_player_control()
|
2017-02-07 23:07:18 +01:00
|
|
|
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if sneak or no path, stop playback
|
2016-01-30 08:56:04 +01:00
|
|
|
if ctrl.sneak or #self.path < 1 then
|
|
|
|
self.driver:set_detach()
|
|
|
|
minetest.chat_send_player(self.driver:get_player_name(), "Playback stopped")
|
|
|
|
self.object:remove()
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- Update position
|
2016-01-30 08:56:04 +01:00
|
|
|
self.object:moveto(self.path[1].pos, true)
|
2017-03-21 17:48:56 +01:00
|
|
|
-- Update yaw/pitch
|
2016-01-30 08:56:04 +01:00
|
|
|
self.driver:set_look_yaw(self.path[1].yaw - (math.pi/2))
|
|
|
|
self.driver:set_look_pitch(0 - self.path[1].pitch)
|
2017-03-21 17:48:56 +01:00
|
|
|
-- Update velocity
|
2016-01-30 08:56:04 +01:00
|
|
|
self.object:setvelocity(self.path[1].velocity)
|
2017-03-21 17:48:56 +01:00
|
|
|
-- Remove path table
|
2016-01-30 08:56:04 +01:00
|
|
|
table.remove(self.path, 1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- Register entity
|
2016-01-30 08:56:04 +01:00
|
|
|
minetest.register_entity("camera:camera", camera)
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
-- Register chatcommand
|
2017-01-20 02:55:19 +01:00
|
|
|
minetest.register_chatcommand("camera", {
|
|
|
|
description = "Manipulate recording",
|
2017-02-07 23:07:18 +01:00
|
|
|
params = "<option> <value>",
|
2017-01-20 02:55:19 +01:00
|
|
|
func = function(name, param)
|
2017-02-07 23:07:18 +01:00
|
|
|
local player = minetest.get_player_by_name(name)
|
|
|
|
local param1, param2 = param:split(" ")[1], param:split(" ")[2]
|
2017-02-07 16:32:06 +01:00
|
|
|
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if play, begin playback preperation
|
2017-02-07 16:32:06 +01:00
|
|
|
if param1 == "play" then
|
|
|
|
local function play(path)
|
|
|
|
local object = minetest.add_entity(player:getpos(), "camera:camera")
|
|
|
|
object:get_luaentity():init(player, 1)
|
|
|
|
object:setyaw(player:get_look_yaw())
|
|
|
|
player:set_attach(object, "", {x=5,y=10,z=0}, {x=0,y=0,z=0})
|
|
|
|
object:get_luaentity().path = path
|
|
|
|
end
|
2017-01-20 02:55:19 +01:00
|
|
|
|
2017-02-07 16:32:06 +01:00
|
|
|
-- Check for param2 (recording name)
|
|
|
|
if param2 and param2 ~= "" then
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if recording exists, start
|
2017-02-07 16:32:06 +01:00
|
|
|
if recordings[name][param2] then
|
|
|
|
play(table.copy(recordings[name][param2]))
|
2017-02-07 23:07:18 +01:00
|
|
|
else -- else, return error
|
2017-02-07 16:32:06 +01:00
|
|
|
return false, "Invalid recording "..param2..". Use /camera list to list recordings."
|
|
|
|
end
|
2017-02-07 23:07:18 +01:00
|
|
|
else -- else, check temp for a recording path
|
2017-02-07 16:32:06 +01:00
|
|
|
if temp[name] then
|
|
|
|
play(table.copy(temp[name]))
|
|
|
|
else
|
|
|
|
return false, "No recordings could be found"
|
|
|
|
end
|
2017-01-20 02:55:19 +01:00
|
|
|
end
|
2017-02-07 16:32:06 +01:00
|
|
|
|
2017-01-20 02:55:19 +01:00
|
|
|
return true, "Playback started"
|
2017-02-07 23:07:18 +01:00
|
|
|
elseif param1 == "save" then -- elseif save, prepare to save path
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if no table for player in recordings, initialize
|
2017-02-07 16:32:06 +01:00
|
|
|
if not recordings[name] then
|
|
|
|
recordings[name] = {}
|
|
|
|
end
|
|
|
|
|
2017-03-21 17:48:56 +01:00
|
|
|
-- if param2 is not blank, save
|
2017-02-07 16:32:06 +01:00
|
|
|
if param2 and param2 ~= "" then
|
|
|
|
recordings[name][param2] = temp[name]
|
2017-03-21 17:48:56 +01:00
|
|
|
return true, "Saved recording as "..param2
|
2017-02-07 23:07:18 +01:00
|
|
|
else -- else, return error
|
2017-02-07 16:32:06 +01:00
|
|
|
return false, "Missing name to save recording under (/camera save <name>)"
|
|
|
|
end
|
2017-03-21 17:48:56 +01:00
|
|
|
elseif param1 == "list" then -- elseif list, list recordings
|
|
|
|
return true, "Recordings: "..get_recordings(name)
|
2017-05-05 09:04:35 +02:00
|
|
|
elseif param1 == "look" then
|
2017-04-30 18:33:03 +02:00
|
|
|
if param2 and param2 ~= "" then
|
|
|
|
if param2 == "nil" then
|
|
|
|
target_look_position = nil
|
2017-05-05 09:04:35 +02:00
|
|
|
return true, "Looking target removed"
|
|
|
|
elseif param2 == "here" then
|
|
|
|
rec_mode = 2
|
|
|
|
target_look_position = player:getpos()
|
|
|
|
return true, "Looking target fixed"
|
2017-04-30 18:33:03 +02:00
|
|
|
else
|
2017-05-05 09:04:35 +02:00
|
|
|
local coord = string.split(param2, ",")
|
|
|
|
if #coord == 3 then
|
|
|
|
target_look_position = {x=tonumber(coord[1]), y=tonumber(coord[2]), z=tonumber(coord[3])}
|
|
|
|
rec_mode = 2
|
|
|
|
return true, "Looking target fixed"
|
|
|
|
else
|
|
|
|
return false, "Wrong formated look coords (/camera look <x,y,z>)"
|
|
|
|
end
|
2017-04-30 18:33:03 +02:00
|
|
|
end
|
|
|
|
else
|
2017-05-05 09:04:35 +02:00
|
|
|
return false, "Missing look parameter (/camera look <nil|here|x,y,z>)"
|
2017-04-30 18:33:03 +02:00
|
|
|
end
|
2017-05-03 22:27:25 +02:00
|
|
|
elseif param1 == "speed" then
|
|
|
|
if param2 and param2 ~= "" then
|
|
|
|
local speed = tonumber(param2)
|
|
|
|
if speed then
|
|
|
|
speed_factor = 1/speed
|
|
|
|
return true, "Speed factor fixed to "..speed_factor
|
|
|
|
else
|
|
|
|
return false, "Invalid speed factor (/camera speed <number>)"
|
|
|
|
end
|
|
|
|
else
|
|
|
|
return false, "Missing speed parameter (/camera speed <number>)"
|
|
|
|
end
|
2017-05-05 09:04:35 +02:00
|
|
|
elseif param1 == "mode" then
|
|
|
|
if param2 and param2 ~= "" then
|
|
|
|
local mode = tonumber(param2)
|
|
|
|
if mode == 0 or mode == 2 then
|
|
|
|
rec_mode = mode
|
|
|
|
return true, "Record mode is set"
|
|
|
|
else
|
|
|
|
return false, "Invalid mode (0: Velocity follow mouse (default), 2: Velocity locked to player first look direction)"
|
|
|
|
end
|
|
|
|
else
|
|
|
|
return false, "Missing mode parameter (/camera mode <0|2>)"
|
|
|
|
end
|
|
|
|
|
2017-02-07 23:07:18 +01:00
|
|
|
else -- else, begin recording
|
2017-04-30 18:33:03 +02:00
|
|
|
player_look_dir = player:get_look_dir()
|
2017-01-20 02:55:19 +01:00
|
|
|
local object = minetest.add_entity(player:getpos(), "camera:camera")
|
2017-05-05 09:04:35 +02:00
|
|
|
object:get_luaentity():init(player, rec_mode)
|
2017-01-20 02:55:19 +01:00
|
|
|
object:setyaw(player:get_look_yaw())
|
|
|
|
player:set_attach(object, "", {x=0,y=10,z=0}, {x=0,y=0,z=0})
|
|
|
|
return true, "Recording started"
|
2016-01-30 08:56:04 +01:00
|
|
|
end
|
|
|
|
end,
|
|
|
|
})
|