Add Gitea deployment workflow and update game assets and scripts
All checks were successful
Deploy to Production / deploy (push) Successful in 8s

This commit is contained in:
Đặng Minh Quang
2026-02-27 10:45:20 +07:00
parent d684ccf1bc
commit 9ca11d046b
9 changed files with 279 additions and 34 deletions

View File

@@ -19347,6 +19347,15 @@ cr.plugins_.SenaPlugin = function (runtime) {
this.bgMusicPlaying = false;
this.bgMusicPaused = false;
this.calculatedPositions = [];
this.customData = {
data1: "",
data2: "",
data3: "",
data4: "",
data5: ""
};
this.lastMessageData = null;
this.lastSenderUUID = "";
};
instanceProto.onDestroy = function () {
if (this.sdk) {
@@ -19382,6 +19391,9 @@ cr.plugins_.SenaPlugin = function (runtime) {
Cnds.prototype.OnPairWrong = function () {
return true;
};
Cnds.prototype.OnMessage = function () {
return true;
};
pluginProto.cnds = new Cnds();
function Acts() {}
Acts.prototype.Load = function () {
@@ -19389,6 +19401,16 @@ cr.plugins_.SenaPlugin = function (runtime) {
var gameCode = this.properties[0] || "G2510S1T30";
if (window["SenaSDK"]) {
this.sdk = new window["SenaSDK"](gameCode);
this.sdk.onCustomMessage = function (data, senderUuid) {
console.log('Runtime received custom message from:', senderUuid);
console.log('Data:', data);
self.lastMessageData = data;
self.lastSenderUUID = senderUuid;
window["SenaTrigger"].runtime.trigger(
cr.plugins_.SenaPlugin.prototype.cnds.OnMessage,
window["SenaTrigger"]
);
};
this.sdk.load(function (success) {
if (success) {
console.log("SDK loaded successfully");
@@ -19512,16 +19534,46 @@ cr.plugins_.SenaPlugin = function (runtime) {
objectWidth,
margin,
maxWidth,
rowBreak,
rowGap,
type,
groupGap
) {
var self = this;
this.calculatedPositions = [];
var totalWidth = count * objectWidth + (count - 1) * margin;
var startX = (maxWidth - totalWidth) / 2;
for (var i = 0; i < count; i++) {
var posX = startX + i * (objectWidth + margin) + objectWidth / 2;
this.calculatedPositions.push(posX);
if (count <= 0) return;
var rows = [];
if (rowBreak > 0) {
for (var i = 0; i < count; i += rowBreak) {
rows.push(Math.min(rowBreak, count - i));
}
} else {
if (count <= 5) {
rows.push(count);
} else {
var top = Math.ceil((count + 1) / 2);
var bottom = count - top;
rows.push(top);
rows.push(bottom);
}
}
console.log("Calculated positions:", this.calculatedPositions);
var baseY = 0;
if (type === "word") {
baseY = groupGap || (rowGap * rows.length); // word always below slot
}
var index = 0;
for (var r = 0; r < rows.length; r++) {
var itemsInRow = rows[r];
var rowWidth = itemsInRow * objectWidth + (itemsInRow - 1) * margin;
var startX = (maxWidth - rowWidth) / 2;
for (var i = 0; i < itemsInRow; i++) {
this.calculatedPositions.push({
x: startX + i * (objectWidth + margin) + objectWidth / 2,
y: baseY + r * rowGap
});
index++;
}
}
console.log("Calculated positions (multi-row):", this.calculatedPositions);
};
Acts.prototype.LoadLevelG5 = function (levelIndex) {
if (this.sdk && this.sdk.loadLevelG5) {
@@ -19546,6 +19598,29 @@ cr.plugins_.SenaPlugin = function (runtime) {
});
}
};
Acts.prototype.SetData = function (data1, data2, data3, data4, data5) {
this.customData.data1 = data1 || "";
this.customData.data2 = data2 || "";
this.customData.data3 = data3 || "";
this.customData.data4 = data4 || "";
this.customData.data5 = data5 || "";
console.log('Custom data set:', this.customData);
};
Acts.prototype.PostMessage = function () {
if (this.sdk && this.sdk.sendMessageToParent) {
var dataToSend = {
data1: this.customData.data1,
data2: this.customData.data2,
data3: this.customData.data3,
data4: this.customData.data4,
data5: this.customData.data5
};
this.sdk.sendMessageToParent(dataToSend);
console.log('Posted message to parent:', dataToSend);
} else {
console.error('SDK not initialized or sendMessageToParent not available');
}
};
pluginProto.acts = new Acts();
function Exps() {}
Exps.prototype.getQuestionValue = function (ret) {
@@ -19687,12 +19762,15 @@ cr.plugins_.SenaPlugin = function (runtime) {
}
};
Exps.prototype.getPosXbyIndex = function (ret, index) {
if (
this.calculatedPositions &&
index >= 0 &&
index < this.calculatedPositions.length
) {
ret.set_float(this.calculatedPositions[index]);
if (this.calculatedPositions[index]) {
ret.set_float(this.calculatedPositions[index].x);
} else {
ret.set_float(0);
}
};
Exps.prototype.getPosYbyIndex = function (ret, index) {
if (this.calculatedPositions[index]) {
ret.set_float(this.calculatedPositions[index].y);
} else {
ret.set_float(0);
}
@@ -19754,7 +19832,11 @@ cr.plugins_.SenaPlugin = function (runtime) {
}
};
Exps.prototype.GetCardType = function (ret, index) {
ret.set_string(this.sdk.getCardType(index));
if (this.sdk && this.sdk.getCardType) {
ret.set_string(this.sdk.getCardType(index));
} else {
ret.set_string("");
}
};
Exps.prototype.getCardID = function (ret, index) {
if (this.sdk && this.sdk.getCardID) {
@@ -19763,6 +19845,24 @@ cr.plugins_.SenaPlugin = function (runtime) {
ret.set_string("");
}
};
Exps.prototype.getData = function (ret, dataIndex) {
var dataKey = "data" + dataIndex;
if (this.customData && this.customData[dataKey] !== undefined) {
ret.set_string(this.customData[dataKey]);
} else {
ret.set_string("");
}
};
Exps.prototype.getLastSenderUUID = function (ret) {
ret.set_string(this.lastSenderUUID || "");
};
Exps.prototype.getLastMessageJSON = function (ret) {
if (this.lastMessageData) {
ret.set_string(JSON.stringify(this.lastMessageData));
} else {
ret.set_string("{}");
}
};
pluginProto.exps = new Exps();
})();
;
@@ -26257,6 +26357,9 @@ cr.getObjectRefTable = function () { return [
cr.system_object.prototype.exps.str,
cr.system_object.prototype.exps.ceil,
cr.system_object.prototype.cnds.TriggerOnce,
cr.plugins_.Sprite.prototype.acts.SetSize,
cr.plugins_.Sprite.prototype.exps.Width,
cr.plugins_.Sprite.prototype.exps.Height,
cr.system_object.prototype.cnds.IsGroupActive,
cr.plugins_.Sprite.prototype.cnds.IsVisible,
cr.behaviors.Flash.prototype.acts.Flash,
@@ -26267,8 +26370,5 @@ cr.getObjectRefTable = function () { return [
cr.behaviors.lunarray_Tween.prototype.acts.Start,
cr.behaviors.Sin.prototype.acts.SetActive,
cr.plugins_.Sprite.prototype.acts.MoveToTop,
cr.plugins_.Audio.prototype.acts.Stop,
cr.plugins_.Sprite.prototype.acts.SetSize,
cr.plugins_.Sprite.prototype.exps.Width,
cr.plugins_.Sprite.prototype.exps.Height
cr.plugins_.Audio.prototype.acts.Stop
];};

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 529 KiB

View File

@@ -81,7 +81,7 @@
<!-- Construct 2 exported games require jQuery. -->
<script src="jquery-3.4.1.min.js"></script>
<script src="tdv_sdk.js"></script>
<script src="sena_sdk.js"></script>

View File

@@ -1,5 +1,5 @@
{
"version": 1770482265,
"version": 1772163638,
"fileList": [
"data.js",
"c2runtime.js",

View File

@@ -50,6 +50,7 @@ function SenaSDK(gid = "G2510S1T30") {
// 'preview' - Timeout 5s rồi fallback sample (testing với data thật)
// 'dev' - Load sample ngay lập tức (development)
this.mode = "preview"; // Default mode
this.role = "student"; // Default role
}
/**
@@ -373,9 +374,15 @@ SenaSDK.prototype.load = function (callback, template = "G2510S1T30") {
self.mode = urlMode.toLowerCase();
}
// THÊM 2 DÒNG NÀY: Lấy role từ URL
const urlRole = urlParams.get("role");
if (urlRole) self.role = urlRole.toLowerCase();
console.log(
"🎮 Sena SDK: Mode =",
self.mode.toUpperCase(),
"| Role =",
self.role || "student",
"| GameCode =",
self.gameCode,
);
@@ -878,14 +885,12 @@ SenaSDK.prototype.guide = function () {
return guide;
};
/**
* Get the question text
* @returns {string} Question or request text
* Get the question text/url
* @returns {string} Question, request text, or URL
*/
SenaSDK.prototype.getQuestionValue = function () {
var q = String(this.data.question || "").trim();
if (q.toLowerCase().startsWith("http")) {
return "";
}
// Đã bỏ chặn URL để có thể lấy link ảnh/audio
return q;
};
/**
@@ -1138,10 +1143,13 @@ SenaSDK.prototype.end = function (answer, callback) {
}
}
// 3. COMPARE (UNORDERED - So sánh không cần thứ tự)
// Sort cả 2 mảng để so sánh tập hợp
const sortedUser = [...userAnswers].sort();
const sortedCorrect = [...correctAnswers].sort();
// 3. COMPARE
// Nếu là Game Type 2 (Sort) thì giữ nguyên thứ tự, nếu không thì sort (unordered)
const isStrictOrder = self.gameType === 2;
const finalUser = isStrictOrder ? [...userAnswers] : [...userAnswers].sort();
const finalCorrect = isStrictOrder
? [...correctAnswers]
: [...correctAnswers].sort();
let isCorrect = false;
@@ -1155,9 +1163,9 @@ SenaSDK.prototype.end = function (answer, callback) {
}
};
if (sortedUser.length === sortedCorrect.length) {
isCorrect = sortedUser.every((uVal, index) => {
let cVal = sortedCorrect[index];
if (finalUser.length === finalCorrect.length) {
isCorrect = finalUser.every((uVal, index) => {
let cVal = finalCorrect[index];
if (uVal === cVal) return true;
// Fuzzy match cho URL (so sánh tên file ảnh)
if (uVal.startsWith("http") || cVal.startsWith("http")) {
@@ -1170,7 +1178,12 @@ SenaSDK.prototype.end = function (answer, callback) {
// -----------------------------------------------------------
// [BƯỚC 1] Kiểm tra Time Limit TRƯỚC (Sửa biến isCorrect)
// -----------------------------------------------------------
if (self.timeLimit > 0 && duration > self.timeLimit) {
// THÊM ĐIỀU KIỆN: Nếu là teacher thì bỏ qua kiểm tra thời gian
if (
self.role !== "teacher" &&
self.timeLimit > 0 &&
duration > self.timeLimit
) {
isCorrect = false; // CHỈ sửa biến boolean, KHÔNG gọi result.isCorrect
console.log("🎮 Sena SDK: Time Limit Exceeded -> Result set to False");
}
@@ -1373,6 +1386,17 @@ SenaSDK.prototype.registerPostMessageListener = function () {
}
break;
case "SEQUENCE_SYNC":
console.log("📥 Sena SDK: Received SEQUENCE_SYNC", event.data);
if (event.data.uuid === self.uuid) {
console.log("🔄 Sena SDK: Own message echoed back, processing...");
}
if (typeof self.onCustomMessage === "function") {
self.onCustomMessage(event.data.data, event.data.uuid);
}
break;
case "SDK_ERROR":
// Server gửi error
console.error("❌ Sena SDK: Received SDK_ERROR", event.data.payload);
@@ -1855,6 +1879,33 @@ SenaSDK.prototype.checkPair = function (idx1, idx2, callback) {
if (callback) callback(isMatch);
};
/**
* [NEW v2.2] Gửi Custom Data lên Parent Window
* @param {Object} data - Object chứa 5 trường data1 -> data5
*/
SenaSDK.prototype.sendMessageToParent = function (data) {
let self = this;
// Tự động tạo UUID cho session nếu chưa có
if (!self.uuid) {
self.uuid =
"session-" + Date.now() + "-" + Math.floor(Math.random() * 10000);
}
// Đóng gói payload đúng chuẩn tài liệu v2.2
let payload = {
type: "SEQUENCE_SYNC",
uuid: self.uuid,
data: data,
timestamp: Date.now(),
};
console.log("📤 Sena SDK: Sending SEQUENCE_SYNC to parent:", payload);
// Gửi lên Parent Window (Backend/Iframe parent)
window.parent.postMessage(payload, "*");
};
if (typeof module !== "undefined" && module.exports) {
module.exports = SenaSDK;
} else if (typeof define === "function" && define.amd) {