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'><h3><a href='https://picklemods.com/'>More Information & Scripts can be found here!</a></h3></div>
<div align='center'><img src='https://michatec.github.io/ptelevision_web/ptelevision.png'/></div>
## 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.
- [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.
## Need Support?
<a href='https://pickle-mods.tebex.io/contact'>Click here!</a>

View File

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

View File

@@ -12,28 +12,11 @@ function CreateNamedRenderTargetForModel(name, model)
return handle
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)
SetTextRenderId(renderTarget) -- set render target
Set_2dLayer(4)
SetScriptGfxDrawBehindPausemenu(1)
--DrawRect(0.5, 0.5, 1.0, 0.5, 255, 0, 0, 255); -- WOAH!
local coords = GetEntityCoords(entity)
local rot = GetEntityRotation(entity)
SetTextRenderId(renderTarget)
SetScriptGfxDrawOrder(4)
SetScriptGfxDrawBehindPausemenu(true)
DrawSprite("ptelevision_b_dict", "ptelevision_b_txd", 0.5, 0.5, 1.0, 1.0, 0.0, 255, 255, 255, 255)
SetTextRenderId(GetDefaultScriptRendertargetRenderId()) -- reset
SetScriptGfxDrawBehindPausemenu(0)
SetTextRenderId(GetDefaultScriptRendertargetRenderId())
SetScriptGfxDrawBehindPausemenu(false)
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
duiObj = nil
tvObj = nil
@@ -37,20 +37,9 @@ local height = 720
local sfHandle = nil
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)
CURRENT_SCREEN = data
sfHandle = loadScaleform(sfName)
sfHandle = lib.requestScaleformMovie(sfName)
runtimeTxd = 'ptelevision_b_dict'
local txd = CreateRuntimeTxd('ptelevision_b_dict')
@@ -105,7 +94,7 @@ function ShowScreen(data)
SetVolume(coords, modelData.DefaultVolume)
end
while duiObj do
local pcoords = GetEntityCoords(PlayerPedId())
local pcoords = GetEntityCoords(cache.ped)
local dist = #(coords - pcoords)
SendDuiMessage(duiObj, json.encode({
setVolume = true,
@@ -129,7 +118,7 @@ end
function GetClosestScreen()
local objPool = GetGamePool('CObject')
local closest = {dist = -1}
local pcoords = GetEntityCoords(PlayerPedId())
local pcoords = GetEntityCoords(cache.ped)
for i=1, #objPool do
local entity = objPool[i]
local model = GetEntityModel(entity)
@@ -165,9 +154,9 @@ Citizen.CreateThread(function()
local wait = 2500
for i=1, #Locations do
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
LoadModel(data.Model)
lib.requestModel(data.Model)
Locations[i].obj = CreateObject(data.Model, data.Position.x, data.Position.y, data.Position.z)
SetEntityHeading(Locations[i].obj, data.Position.w)
FreezeEntityPosition(Locations[i].obj, true)
@@ -207,11 +196,9 @@ RegisterNetEvent("ptelevision:requestSync", function(coords, data)
end
end)
RegisterNUICallback("pageLoaded", function(cb)
RegisterNUICallback("pageLoaded", function(data, cb)
waitForLoad = false
if cb then cb() end
cb(1)
end)
AddEventHandler('onResourceStop', function(name)

View File

@@ -1,4 +1,4 @@
TelevisionsLocal = {}
local TelevisionsLocal = {}
function SetChannel(index)
TriggerServerEvent("ptelevision:event", CURRENT_SCREEN, "ptv_status", {
@@ -20,8 +20,8 @@ function GetChannelList()
channel = status.channel
end
for index,value in pairs(Channels) do
table.insert(channel_list, {index = index, url = value.url})
table.insert(menu_list, "Channel #" .. index .. " (".. value.name ..")")
channel_list[#channel_list+1] = {index = index, url = value.url}
menu_list[#menu_list+1] = "Channel #" .. index .. " (".. value.name ..")"
if channel ~= nil and channel == index then
current = #channel_list
end
@@ -59,11 +59,17 @@ end
function VideoMenu()
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
TriggerServerEvent("ptelevision:event", CURRENT_SCREEN, "ptv_status", {
type = "play",
url = input[1]
url = input[1],
loop = input[2],
showControls = input[3]
})
end
Citizen.Wait(300)
@@ -95,10 +101,6 @@ function OpenTVMenu()
SetChannel(ChannelList.list[scrollIndex].index)
end
end,
onSelected = function(selected, scrollIndex, args)
end,
onClose = function(keyPressed)
end,
options = {
{label = 'Videos', description = 'Play a video or stream on the screen.'},
{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
local event = value
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
data = Channels[event.channel]
data.channel = event.channel
@@ -219,8 +221,9 @@ end)
RegisterCommand('tv', function()
OpenTVMenu()
end)
end, false)
RegisterCommand("broadcast", function(source, args, raw)
RegisterCommand('broadcast', function()
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,
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.
@@ -152,3 +166,4 @@ Config.Events = { -- Events for approving broadcasts / interactions (due to popu
cb()
end,
}

View File

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

View File

@@ -1,110 +1,127 @@
var player;
var playerData;
$(document).ready(function() {
$.post("https://ptelevision/pageLoaded", JSON.stringify({}))
})
function GetURLID(link) {
if (link == null) return;
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);
if (match && match[2].length == 11) {
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] };
}
}
function ChannelDisplay(channel, channelFound) {
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) {
temp += channel
temp += channel;
} else {
temp += "0" + channel;
}
else {
temp += ("0" + channel)
}
$("#overlay span").show()
$("#overlay span").html(temp)
}
else {
$("#overlay span").show()
$("#overlay span").html("")
$("#overlay span").show();
$("#overlay span").html(temp);
} else {
$("#overlay span").show();
$("#overlay span").html("");
}
if (channelFound) {
$("#tv-container").hide()
}
else {
$("#tv-container").show()
$("#tv-container").hide();
} else {
$("#tv-container").show();
}
}
function SetVideo(video_data) {
var url = video_data.url;
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) {
player.destroy()
player.destroy();
player = null;
}
if (data) {
if (data.type == "youtube") {
player = new YT.Player('twitch-embed', {
height: '100%',
width: '100%',
if (loop == true) {
player = new YT.Player("twitch-embed", {
height: "100%",
width: "100%",
videoId: data.id,
playerVars: {
'playsinline': 1,
playsinline: 1,
loop: 1,
playlist: data.id,
controls: showControls,
},
events: {
'onReady': function(event) {
onReady: function (event) {
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) {
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", {
width: "100%",
height: "100%",
channel: data.id,
volume: 1.0
volume: 1.0,
});
player.addEventListener(Twitch.Embed.VIDEO_READY, function () {
player.setMuted(false);
});
}
$("#overlay span").hide()
$("#tv-container").hide()
$("#overlay span").hide();
$("#tv-container").hide();
}
if (channel) {
ChannelDisplay(channel, url)
ChannelDisplay(channel, url);
}
}
function SetVolume(volume) {
if (player && playerData && player.setVolume) {
if (playerData.type == "twitch") {
player.setMuted(false);
player.setVolume(volume / 100.0);
}
else if (playerData.type == "youtube") {
} else if (playerData.type == "youtube") {
player.unMute();
player.setVolume(volume);
}
@@ -112,33 +129,37 @@ function SetVolume(volume) {
}
function ShowNotification(channel, data) {
$("#tv-container").addClass("notify")
$("#tv-container div").addClass("notify")
var display = $('#tv-container').is(':visible')
$('#tv-container').show()
$("#tv-container div").html("Channel #" + channel + (data ? (" ("+data.name+")") : "") + " is now " + (data ? "live!" : "offline."))
$("#tv-container").addClass("notify");
$("#tv-container div").addClass("notify");
var display = $("#tv-container").is(":visible");
$("#tv-container").show();
$("#tv-container div").html(
"Channel #" +
channel +
(data ? " (" + data.name + ")" : "") +
" is now " +
(data ? "live!" : "offline.")
);
setTimeout(function () {
$("#tv-container").removeClass("notify")
$("#tv-container div").removeClass("notify")
$("#tv-container div").html("NO SIGNAL")
$("#tv-container").removeClass("notify");
$("#tv-container div").removeClass("notify");
$("#tv-container div").html("NO SIGNAL");
if (!display) {
$('#tv-container').hide()
$("#tv-container").hide();
}
}, 3500)
}, 3500);
}
window.addEventListener("message", function (ev) {
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 () {
ChannelDisplay()
})
ChannelDisplay();
});