Repository navigation
Expand file tree
/
Copy pathEngine.lua
More file actions
147 lines (144 loc) · 7.33 KB
/
Copy pathEngine.lua
File metadata and controls
147 lines (144 loc) · 7.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
-- WoW 3.3.5 / Lua 5.1. No loadstring, RunScript or arbitrary GM commands.
ProjectJaina_IntiObjGPS = { prefix = "INTIGPS1", realm = "Inti (Pruebas)", maxObjects = 200, maxLetters = 40000 }
local M = ProjectJaina_IntiObjGPS
local SCALE_MIN, SCALE_MAX = 0.01, 50
local function valid(s, integer, min, max)
local n = tonumber(s)
return n and n == n and n >= min and n <= max and (not integer or n == math.floor(n))
end
function M.Parse(text)
if #text > M.maxLetters then return nil, "Texto demasiado largo (maximo " .. M.maxLetters .. " caracteres)." end
local rows, words, lineByWord, line, lastPos = {}, {}, {}, 1, 1
for start, token in text:gmatch("()(%S+)") do
local _, breaks = text:sub(lastPos, start - 1):gsub("\n", "")
line = line + breaks
words[#words + 1] = token
lineByWord[#lineByWord + 1] = line
lastPos = start + #token
end
local i = 1
while i <= #words do
if words[i] ~= ".objgps" then
return nil, "Linea " .. (lineByWord[i] or line) .. ": usa .objgps ENTRY MAPA X Y Z O ESCALA."
end
local start, nextCommand = i, nil
for j = i + 1, math.min(#words, i + 9) do
if words[j] == ".objgps" then nextCommand = j; break end
end
local stop = nextCommand and (nextCommand - 1) or math.min(#words, i + 8)
local count = stop - start + 1
if count ~= 8 then
return nil, "Linea " .. (lineByWord[start] or line) .. ": usa .objgps ENTRY MAPA X Y Z O ESCALA."
end
local a = {}
for j = start, stop do a[#a + 1] = words[j] end
if not (valid(a[2], true, 1, 4294967295) and valid(a[3], true, 0, 65535) and
valid(a[4], false, -17066, 17066) and valid(a[5], false, -17066, 17066) and
valid(a[6], false, -17066, 17066) and valid(a[7], false, -100000, 100000) and
valid(a[8], false, SCALE_MIN, SCALE_MAX)) then
return nil, "Linea " .. (lineByWord[start] or line) .. ": numero invalido. Usa punto decimal; escala entre 0.01 y 50."
end
local data = table.concat(a, " ", 2)
if #data > 220 then return nil, "Linea " .. (lineByWord[start] or line) .. " demasiado larga." end
rows[#rows + 1] = { data = data, source = lineByWord[start] or line }
if #rows > M.maxObjects then return nil, "Maximo " .. M.maxObjects .. " objetos por lote." end
i = stop + 1
end
if #rows == 0 then return nil, "Pega al menos una linea .objgps." end
return rows
end
-- Stop-and-wait upload: at most one command outstanding, no automatic retry.
function M.New(send, clock, notify, allowed)
local e = { state = "idle", done = 0, serial = 0 }
function e:Status(state, message)
self.state = state
notify(state, message)
end
function e:Transmit(op)
if not allowed() then self:Status("error", "Solo funciona conectado a Inti (Pruebas)."); return false end
self.deadline = clock() + 15
send(".objgpsbatch " .. self.token .. " " .. op)
return true
end
function e:Validate(text, seed)
if self.state == "uploading" or self.state == "running" or self.state == "starting" or self.state == "stopping" then return end
local rows, err = M.Parse(text)
if not rows then self:Status("error", err); return end
if not allowed() then self:Status("error", "Solo funciona conectado a Inti (Pruebas)."); return end
self.serial = self.serial + 1
self.token = tostring(seed) .. "_" .. self.serial
self.rows, self.source, self.index, self.done = rows, text, 0, 0
self:Status("uploading", "Validando " .. #rows .. " objetos en Inti; no se crea nada...")
self:Transmit("begin " .. #rows)
end
function e:NextRow()
self.index = self.index + 1
self:Transmit("row " .. self.index .. " " .. self.rows[self.index].data)
end
function e:Receive(message)
local token, kind, detail = message:match("^([^|]+)|([^|]+)|(.*)$")
if token ~= self.token or not allowed() then return end
if kind == "ERROR" then
self.nextSend, self.deadline = nil, nil
self:Status("error", detail)
elseif kind == "STOP" then
self.nextSend, self.deadline = nil, nil
self:Status("stopped", detail)
elseif self.state == "uploading" then
if kind == "BEGIN" and self.index == 0 and tonumber(detail) == #self.rows then
self.deadline, self.nextSend = nil, clock() + 0.5
elseif kind == "ROW" and tonumber(detail) == self.index and self.index < #self.rows then
self.deadline, self.nextSend = nil, clock() + 0.5
elseif kind == "READY" and self.index == #self.rows and tonumber(detail) == #self.rows then
self.deadline, self.readyUntil = nil, clock() + 170
self:Status("ready", #self.rows .. " objetos validados. Ejecutar los guardara permanentemente.")
end
elseif kind == "RUNNING" and self.state == "starting" then
self.deadline = clock() + 15
self:Status("running", "Creando y verificando cada objeto...")
elseif kind == "PLACED" and (self.state == "running" or self.state == "stopping") then
local row, guid, entry, scale = detail:match("^(%d+) (%d+) (%d+) ([%d%.%-]+)$")
row = tonumber(row)
if row and self.rows and self.rows[row] and row == self.done + 1 then
self.done, self.deadline = row, clock() + 15
notify("placed", "Linea " .. self.rows[row].source .. ": entry " .. entry .. ", GUID " .. guid ..
", escala " .. scale .. " | .gobject delete " .. guid)
end
elseif kind == "DONE" and (self.state == "running" or self.state == "stopping") then
self.deadline = nil
self:Status("done", detail .. " objetos guardados. No se ejecutara otra vez este lote.")
end
end
function e:Run(text)
if self.state ~= "ready" then return end
if text ~= self.source then self:Status("error", "El texto cambio. Vuelve a validar."); return end
if clock() > self.readyUntil then self:Status("error", "La validacion vencio. Valida otra vez."); return end
self:Status("starting", "Enviando ejecucion a Inti...")
self:Transmit("run")
end
function e:Cancel()
if not self.token then return end
self.nextSend = nil
self:Status("stopping", "Solicitando detener; los objetos ya creados permanecen.")
self:Transmit("cancel")
end
function e:Changed()
if self.state == "ready" or self.state == "uploading" or self.state == "starting" or self.state == "running" then self:Cancel() end
end
function e:Update()
if self.nextSend and clock() >= self.nextSend then
self.nextSend = nil
self:NextRow()
elseif self.deadline and clock() > self.deadline then
self.deadline = nil
if self.state == "running" or self.state == "starting" then
self:Cancel()
else
self:Status("error", "Sin respuesta del Lua de Inti. No se reintenta. Revisa el registro antes de repetir.")
end
elseif self.state == "ready" and clock() > self.readyUntil then
self:Status("error", "Validacion vencida; vuelve a validar.")
end
end
return e
end