Compare commits

15 Commits

Author SHA1 Message Date
Michachatz
67b71a8912 Update README.md 2025-11-02 00:52:23 +01:00
Michachatz
81e777ae9c Update fxmanifest.lua 2025-11-02 00:40:28 +01:00
Michachatz
acfc0b6232 Update config.lua 2025-11-02 00:39:49 +01:00
Michachatz
d3ed042bdd Update tv.lua 2025-11-02 00:37:42 +01:00
Michachatz
081d452f49 Update main.js 2025-11-02 00:34:19 +01:00
Michachatz
969ce331e6 Update tv.lua 2025-11-02 00:32:54 +01:00
Michachatz
0f082b4114 Update main.lua 2025-11-02 00:32:30 +01:00
Michachatz
95ec3294b8 Update dui.lua 2025-11-02 00:31:41 +01:00
Michachatz
42152a844e Update cursor.lua 2025-11-02 00:31:19 +01:00
Michachatz
f67f8496df Update main.lua 2025-11-02 00:26:00 +01:00
Michachatz
ee703e04d1 Update README.md 2025-11-02 00:24:32 +01:00
Michachatz
54fae17c32 Update default URL for Dui object 2025-11-02 00:18:01 +01:00
Michachatz
fc55ac2d27 Delete .github/FUNDING.yml 2025-11-02 00:11:38 +01:00
Michachatz
f4d70a0741 Refactor main.js for improved readability 2025-11-02 00:10:28 +01:00
Michachatz
80b6fcf380 Update renderer link and clean up README content 2025-11-01 23:59:41 +01:00
9 changed files with 197 additions and 193 deletions

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
ko_fi: picklemods

View File

@@ -1,5 +1,4 @@
<div align='center'><img src='https://user-images.githubusercontent.com/111543470/198868741-d78353cf-0576-4f2e-8554-1f7e4ef4c986.png'/></div> <div align='center'><img src='https://michatec.github.io/ptelevision_web/ptelevision.png'/></div>
<div align='center'><h3><a href='https://picklemods.com/'>More Information & Scripts can be found here!</a></h3></div>
## What is this? ## What is this?
@@ -16,12 +15,8 @@ With this resource, you will be able to do the following:
You will need the following for this script to work. You will need the following for this script to work.
- [Ox Lib](https://github.com/overextended/ox_lib/releases) (works with any framework) - [Ox Lib](https://github.com/CommunityOx/ox_lib/releases) (works with any framework)
- [Renderer](https://forum.cfx.re/t/release-generic-dui-2d-3d-renderer/131208) (works with any framework) - [Renderer](https://github.com/Michatec/ptelevision/releases/tag/renderer_gfx) (works with any framework)
If you want to make a fork, please obtain permission with a valid reason. If you want to make a fork, please obtain permission with a valid reason.
## Need Support?
<a href='https://pickle-mods.tebex.io/contact'>Click here!</a>

View File

@@ -1,7 +1,7 @@
local scale = 1.5 local scale = 1.5
local screenWidth = math.floor(1920 / scale) local screenWidth = math.floor(1920 / scale)
local screenHeight = math.floor(1080 / scale) local screenHeight = math.floor(1080 / scale)
shouldDraw = false local shouldDraw = false
function SetInteractScreen(bool) function SetInteractScreen(bool)
if (not shouldDraw and bool) then if (not shouldDraw and bool) then
@@ -19,7 +19,7 @@ function SetInteractScreen(bool)
local minY, maxY = ((h - (h / 2)) / 2), (h - (h / 4)) local minY, maxY = ((h - (h / 2)) / 2), (h - (h / 4))
local totalY = minY - maxY local totalY = minY - maxY
RequestTextureDictionary('fib_pc') lib.requestStreamedTextureDict('fib_pc')
-- Update controls while active -- Update controls while active
while shouldDraw do while shouldDraw do
@@ -27,7 +27,7 @@ function SetInteractScreen(bool)
nY = GetControlNormal(0, 240) * screenHeight nY = GetControlNormal(0, 240) * screenHeight
DisableControlAction(0, 1, true) -- Disable looking horizontally DisableControlAction(0, 1, true) -- Disable looking horizontally
DisableControlAction(0, 2, true) -- Disable looking vertically DisableControlAction(0, 2, true) -- Disable looking vertically
DisablePlayerFiring(PlayerPedId(), true) -- Disable weapon firing DisablePlayerFiring(cache.ped, true) -- Disable weapon firing
DisableControlAction(0, 142, true) -- Disable aiming DisableControlAction(0, 142, true) -- Disable aiming
DisableControlAction(0, 106, true) -- Disable in-game mouse controls DisableControlAction(0, 106, true) -- Disable in-game mouse controls
-- Update mouse position when changed -- Update mouse position when changed

View File

@@ -12,28 +12,11 @@ function CreateNamedRenderTargetForModel(name, model)
return handle return handle
end end
function RequestTextureDictionary(dict)
RequestStreamedTextureDict(dict)
while not HasStreamedTextureDictLoaded(dict) do Wait(0) end
return dict
end
function LoadModel(model)
if not IsModelInCdimage(model) then return end
RequestModel(model)
while not HasModelLoaded(model) do Wait(0) end
return model
end
function RenderScaleformTV(renderTarget, scaleform, entity) function RenderScaleformTV(renderTarget, scaleform, entity)
SetTextRenderId(renderTarget) -- set render target SetTextRenderId(renderTarget)
Set_2dLayer(4) SetScriptGfxDrawOrder(4)
SetScriptGfxDrawBehindPausemenu(1) SetScriptGfxDrawBehindPausemenu(true)
--DrawRect(0.5, 0.5, 1.0, 0.5, 255, 0, 0, 255); -- WOAH!
local coords = GetEntityCoords(entity)
local rot = GetEntityRotation(entity)
DrawSprite("ptelevision_b_dict", "ptelevision_b_txd", 0.5, 0.5, 1.0, 1.0, 0.0, 255, 255, 255, 255) DrawSprite("ptelevision_b_dict", "ptelevision_b_txd", 0.5, 0.5, 1.0, 1.0, 0.0, 255, 255, 255, 255)
SetTextRenderId(GetDefaultScriptRendertargetRenderId()) -- reset SetTextRenderId(GetDefaultScriptRendertargetRenderId())
SetScriptGfxDrawBehindPausemenu(0) SetScriptGfxDrawBehindPausemenu(false)
end end

View File

@@ -1,4 +1,4 @@
DEFAULT_URL = "https://cfx-nui-ptelevision/html/index.html" DEFAULT_URL = "https://michatec.github.io/ptelevision_web/index.html"
duiUrl = DEFAULT_URL duiUrl = DEFAULT_URL
duiObj = nil duiObj = nil
tvObj = nil tvObj = nil
@@ -37,20 +37,9 @@ local height = 720
local sfHandle = nil local sfHandle = nil
local txdHasBeenSet = false local txdHasBeenSet = false
function loadScaleform(scaleform)
local scaleformHandle = RequestScaleformMovie(scaleform)
while not HasScaleformMovieLoaded(scaleformHandle) do
scaleformHandle = RequestScaleformMovie(scaleform)
Citizen.Wait(0)
end
return scaleformHandle
end
function ShowScreen(data) function ShowScreen(data)
CURRENT_SCREEN = data CURRENT_SCREEN = data
sfHandle = loadScaleform(sfName) sfHandle = lib.requestScaleformMovie(sfName)
runtimeTxd = 'ptelevision_b_dict' runtimeTxd = 'ptelevision_b_dict'
local txd = CreateRuntimeTxd('ptelevision_b_dict') local txd = CreateRuntimeTxd('ptelevision_b_dict')
@@ -105,7 +94,7 @@ function ShowScreen(data)
SetVolume(coords, modelData.DefaultVolume) SetVolume(coords, modelData.DefaultVolume)
end end
while duiObj do while duiObj do
local pcoords = GetEntityCoords(PlayerPedId()) local pcoords = GetEntityCoords(cache.ped)
local dist = #(coords - pcoords) local dist = #(coords - pcoords)
SendDuiMessage(duiObj, json.encode({ SendDuiMessage(duiObj, json.encode({
setVolume = true, setVolume = true,
@@ -129,7 +118,7 @@ end
function GetClosestScreen() function GetClosestScreen()
local objPool = GetGamePool('CObject') local objPool = GetGamePool('CObject')
local closest = {dist = -1} local closest = {dist = -1}
local pcoords = GetEntityCoords(PlayerPedId()) local pcoords = GetEntityCoords(cache.ped)
for i=1, #objPool do for i=1, #objPool do
local entity = objPool[i] local entity = objPool[i]
local model = GetEntityModel(entity) local model = GetEntityModel(entity)
@@ -165,9 +154,9 @@ Citizen.CreateThread(function()
local wait = 2500 local wait = 2500
for i=1, #Locations do for i=1, #Locations do
local data = Locations[i] local data = Locations[i]
local dist = #(GetEntityCoords(PlayerPedId()) - v3(data.Position)) local dist = #(GetEntityCoords(cache.ped) - v3(data.Position))
if not Locations[i].obj and dist < 20.0 then if not Locations[i].obj and dist < 20.0 then
LoadModel(data.Model) lib.requestModel(data.Model)
Locations[i].obj = CreateObject(data.Model, data.Position.x, data.Position.y, data.Position.z) Locations[i].obj = CreateObject(data.Model, data.Position.x, data.Position.y, data.Position.z)
SetEntityHeading(Locations[i].obj, data.Position.w) SetEntityHeading(Locations[i].obj, data.Position.w)
FreezeEntityPosition(Locations[i].obj, true) FreezeEntityPosition(Locations[i].obj, true)
@@ -207,11 +196,9 @@ RegisterNetEvent("ptelevision:requestSync", function(coords, data)
end end
end) end)
RegisterNUICallback("pageLoaded", function(data, cb)
RegisterNUICallback("pageLoaded", function(cb)
waitForLoad = false waitForLoad = false
if cb then cb() end cb(1)
end) end)
AddEventHandler('onResourceStop', function(name) AddEventHandler('onResourceStop', function(name)

View File

@@ -1,4 +1,4 @@
TelevisionsLocal = {} local TelevisionsLocal = {}
function SetChannel(index) function SetChannel(index)
TriggerServerEvent("ptelevision:event", CURRENT_SCREEN, "ptv_status", { TriggerServerEvent("ptelevision:event", CURRENT_SCREEN, "ptv_status", {
@@ -20,8 +20,8 @@ function GetChannelList()
channel = status.channel channel = status.channel
end end
for index,value in pairs(Channels) do for index,value in pairs(Channels) do
table.insert(channel_list, {index = index, url = value.url}) channel_list[#channel_list+1] = {index = index, url = value.url}
table.insert(menu_list, "Channel #" .. index .. " (".. value.name ..")") menu_list[#menu_list+1] = "Channel #" .. index .. " (".. value.name ..")"
if channel ~= nil and channel == index then if channel ~= nil and channel == index then
current = #channel_list current = #channel_list
end end
@@ -59,11 +59,17 @@ end
function VideoMenu() function VideoMenu()
lib.hideMenu() lib.hideMenu()
local input = lib.inputDialog('Video Player', {'URL:'}) local input = lib.inputDialog('Video Player', {
{ type = 'input', label = 'Video URL' },
{ type = 'checkbox', label = 'Loop Video' },
{ type = 'checkbox', label = 'Show Video Controls' }
})
if input then if input then
TriggerServerEvent("ptelevision:event", CURRENT_SCREEN, "ptv_status", { TriggerServerEvent("ptelevision:event", CURRENT_SCREEN, "ptv_status", {
type = "play", type = "play",
url = input[1] url = input[1],
loop = input[2],
showControls = input[3]
}) })
end end
Citizen.Wait(300) Citizen.Wait(300)
@@ -95,10 +101,6 @@ function OpenTVMenu()
SetChannel(ChannelList.list[scrollIndex].index) SetChannel(ChannelList.list[scrollIndex].index)
end end
end, end,
onSelected = function(selected, scrollIndex, args)
end,
onClose = function(keyPressed)
end,
options = { options = {
{label = 'Videos', description = 'Play a video or stream on the screen.'}, {label = 'Videos', description = 'Play a video or stream on the screen.'},
{label = 'Web Browser', description = 'Access the web via your TV.'}, {label = 'Web Browser', description = 'Access the web via your TV.'},
@@ -185,7 +187,7 @@ RegisterNetEvent("ptelevision:event", function(data, index, key, value)
if (index) then if (index) then
local event = value local event = value
if (event.type == "play") then if (event.type == "play") then
local data = { url = event.url } local data = { url = event.url, loop = event.loop, showControls = event.showControls }
if (event.channel) then if (event.channel) then
data = Channels[event.channel] data = Channels[event.channel]
data.channel = event.channel data.channel = event.channel
@@ -219,8 +221,9 @@ end)
RegisterCommand('tv', function() RegisterCommand('tv', function()
OpenTVMenu() OpenTVMenu()
end) end, false)
RegisterCommand("broadcast", function(source, args, raw) RegisterCommand('broadcast', function()
BroadcastMenu() BroadcastMenu()
end) end, false)

View File

@@ -120,6 +120,20 @@ Config.Models = { -- Any TV Models used on the map or in locations must be defin
Scale = 0.085, Scale = 0.085,
Offset = vector3(-1.02, -0.055, 1.04) Offset = vector3(-1.02, -0.055, 1.04)
}, },
[-240931727] = { --Casino Penthouse Theater Room
DefaultVolume = 0.5,
Range = 20.0,
Target = "tvscreen", -- Only use if prop has render-target name.
Scale = 0.085,
Offset = vector3(-1.02, -0.055, 1.04)
},
[`v_ilev_cin_screen`] = { --Cinema/Theater Screen
DefaultVolume = 0.5,
Range = 60.0,
Target = "cinscreen", -- Only use if prop has render-target name.
Scale = 0.085,
Offset = vector3(-1.02, -0.055, 1.04)
},
} }
Config.Locations = { -- REMOVE ALL IF NOT USING ONESYNC, OR IT SHALL BREAK. Config.Locations = { -- REMOVE ALL IF NOT USING ONESYNC, OR IT SHALL BREAK.
@@ -152,3 +166,4 @@ Config.Events = { -- Events for approving broadcasts / interactions (due to popu
cb() cb()
end, end,
} }

View File

@@ -1,7 +1,7 @@
fx_version "cerulean" fx_version "cerulean"
game "gta5" game "gta5"
author "Pickle Mods#0001" author "Pickle Mods & Michatec"
version "v1.2.5" version "v1.2.6"
ui_page "html/blank.html" ui_page "html/blank.html"
files { files {
@@ -30,3 +30,4 @@ server_scripts {
} }
lua54 'yes' lua54 'yes'

View File

@@ -1,110 +1,127 @@
var player; var player;
var playerData; var playerData;
$(document).ready(function() {
$.post("https://ptelevision/pageLoaded", JSON.stringify({}))
})
function GetURLID(link) { function GetURLID(link) {
if (link == null) return; if (link == null) return;
let url = link.toString(); let url = link.toString();
var regExp = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/; var regExp =
/^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
var match = url.match(regExp); var match = url.match(regExp);
if (match && match[2].length == 11) { if (match && match[2].length == 11) {
return { type: "youtube", id: match[2] }; return { type: "youtube", id: match[2] };
} } else if (url.split("twitch.tv/").length > 1) {
else if (url.split("twitch.tv/").length > 1) {
return { type: "twitch", id: url.split("twitch.tv/")[1] }; return { type: "twitch", id: url.split("twitch.tv/")[1] };
} }
} }
function ChannelDisplay(channel, channelFound) { function ChannelDisplay(channel, channelFound) {
if (channel) { if (channel) {
var temp = 'CH<span style="font-size: 18pt !important;"> </span>' var temp = 'CH<span style="font-size: 18pt !important;"> </span>';
if (channel > 9) { if (channel > 9) {
temp += channel temp += channel;
} else {
temp += "0" + channel;
} }
else { $("#overlay span").show();
temp += ("0" + channel) $("#overlay span").html(temp);
} } else {
$("#overlay span").show() $("#overlay span").show();
$("#overlay span").html(temp) $("#overlay span").html("");
}
else {
$("#overlay span").show()
$("#overlay span").html("")
} }
if (channelFound) { if (channelFound) {
$("#tv-container").hide() $("#tv-container").hide();
} } else {
else { $("#tv-container").show();
$("#tv-container").show()
} }
} }
function SetVideo(video_data) { function SetVideo(video_data) {
var url = video_data.url; var url = video_data.url;
var channel = video_data.channel; var channel = video_data.channel;
var data = GetURLID(url) var loop = video_data.loop;
var showControls = Number(video_data.showControls);
var data = GetURLID(url);
playerData = data playerData = data;
if (player) { if (player) {
player.destroy() player.destroy();
player = null; player = null;
} }
if (data) { if (data) {
if (data.type == "youtube") { if (data.type == "youtube") {
player = new YT.Player('twitch-embed', { if (loop == true) {
height: '100%', player = new YT.Player("twitch-embed", {
width: '100%', height: "100%",
width: "100%",
videoId: data.id, videoId: data.id,
playerVars: { playerVars: {
'playsinline': 1, playsinline: 1,
loop: 1,
playlist: data.id,
controls: showControls,
}, },
events: { events: {
'onReady': function(event) { onReady: function (event) {
event.target.playVideo(); event.target.playVideo();
event.target.seekTo(video_data.time) event.target.seekTo(video_data.time);
}, },
'onStateChange': function(event) { onStateChange: function (event) {
if (event.data == YT.PlayerState.PLAYING) { if (event.data == YT.PlayerState.PLAYING) {
event.target.unMute(); event.target.unMute();
} else if (event.data == YT.PlayerState.PAUSED) {
} }
else if (event.data == YT.PlayerState.PAUSED) { },
},
} });
} } else {
player = new YT.Player("twitch-embed", {
height: "100%",
width: "100%",
videoId: data.id,
playerVars: {
playsinline: 1,
controls: showControls,
},
events: {
onReady: function (event) {
event.target.playVideo();
event.target.seekTo(video_data.time);
},
onStateChange: function (event) {
if (event.data == YT.PlayerState.PLAYING) {
event.target.unMute();
} else if (event.data == YT.PlayerState.PAUSED) {
} }
},
},
}); });
} }
else if (data.type == "twitch") { } else if (data.type == "twitch") {
player = new Twitch.Player("twitch-embed", { player = new Twitch.Player("twitch-embed", {
width: "100%", width: "100%",
height: "100%", height: "100%",
channel: data.id, channel: data.id,
volume: 1.0 volume: 1.0,
}); });
player.addEventListener(Twitch.Embed.VIDEO_READY, function () { player.addEventListener(Twitch.Embed.VIDEO_READY, function () {
player.setMuted(false); player.setMuted(false);
}); });
} }
$("#overlay span").hide() $("#overlay span").hide();
$("#tv-container").hide() $("#tv-container").hide();
} }
if (channel) { if (channel) {
ChannelDisplay(channel, url) ChannelDisplay(channel, url);
} }
} }
function SetVolume(volume) { function SetVolume(volume) {
if (player && playerData && player.setVolume) { if (player && playerData && player.setVolume) {
if (playerData.type == "twitch") { if (playerData.type == "twitch") {
player.setMuted(false); player.setMuted(false);
player.setVolume(volume / 100.0); player.setVolume(volume / 100.0);
} } else if (playerData.type == "youtube") {
else if (playerData.type == "youtube") {
player.unMute(); player.unMute();
player.setVolume(volume); player.setVolume(volume);
} }
@@ -112,33 +129,37 @@ function SetVolume(volume) {
} }
function ShowNotification(channel, data) { function ShowNotification(channel, data) {
$("#tv-container").addClass("notify") $("#tv-container").addClass("notify");
$("#tv-container div").addClass("notify") $("#tv-container div").addClass("notify");
var display = $('#tv-container').is(':visible') var display = $("#tv-container").is(":visible");
$('#tv-container').show() $("#tv-container").show();
$("#tv-container div").html("Channel #" + channel + (data ? (" ("+data.name+")") : "") + " is now " + (data ? "live!" : "offline.")) $("#tv-container div").html(
"Channel #" +
channel +
(data ? " (" + data.name + ")" : "") +
" is now " +
(data ? "live!" : "offline.")
);
setTimeout(function () { setTimeout(function () {
$("#tv-container").removeClass("notify") $("#tv-container").removeClass("notify");
$("#tv-container div").removeClass("notify") $("#tv-container div").removeClass("notify");
$("#tv-container div").html("NO SIGNAL") $("#tv-container div").html("NO SIGNAL");
if (!display) { if (!display) {
$('#tv-container').hide() $("#tv-container").hide();
} }
}, 3500) }, 3500);
} }
window.addEventListener("message", function (ev) { window.addEventListener("message", function (ev) {
if (ev.data.setVideo) { if (ev.data.setVideo) {
SetVideo(ev.data.data) SetVideo(ev.data.data);
} else if (ev.data.setVolume) {
SetVolume(ev.data.data);
} else if (ev.data.showNotification) {
ShowNotification(ev.data.channel, ev.data.data);
} }
else if (ev.data.setVolume) { });
SetVolume(ev.data.data)
}
else if (ev.data.showNotification) {
ShowNotification(ev.data.channel, ev.data.data)
}
})
$(document).ready(function () { $(document).ready(function () {
ChannelDisplay() ChannelDisplay();
}) });