class LocalStoragePseudoCloud {

constructor() {

this.peer = null;

this.conn = null;

this.isHost = false;

this.VAR_PREFIX = 'pm_var_';

this.LIST_PREFIX = 'pm_list_';

this.LOG_KEY = 'pm_local_log';

this.BANNED_USERS_KEY = 'pm_banned_users';

this.WARNINGS_KEY = 'pm_user_warnings';

this.BANNED_WORDS_KEY = 'pm_banned_words';

this.ALLOWED_USER = 'ralsei-';

this.messageCooldown = 2000; // 2 seconds per message

this.lastMessageTime = {};

// Default banned words

const defaultBannedWords = ["hate rals","hate ral","hate ralsii","hate ralsie","hate alsyi","hate boss_dunkun","fuck","bitch","hate ralsei","fucking",67,"6 7",69,"sex","s3x","p0rn","porn","six seven","sixty seven","6-7","fuk","fuc","fck","fkk","fak","nigger","niger"," n1993r","n1gg3r","nigg3r","n1ger","n193r","n i g g e r","niger","niga","n1g4","n1ga","nig4","n i g 4","n 1 g a","nigar","n1g4r","/ban @s"];

if(!localStorage.getItem(this.BANNED_WORDS_KEY)){

localStorage.setItem(this.BANNED_WORDS_KEY, JSON.stringify(defaultBannedWords));

}

// Auto-load PeerJS

if (typeof Peer === 'undefined') {

const s = document.createElement('script');

s.src = 'https://unpkg.com/[email protected]/dist/peerjs.min.js';

s.onload = () => console.log('PeerJS loaded.');

document.head.appendChild(s);

}

}

getInfo() {

return {

id: 'LocalStoragePseudoCloud',

name: 'Local Storage Cloud (WebRTC) Advanced',

color1: '#5ba58c',

color2: '#4b8d78',

blocks: [

// VARIABLES

{ opcode: 'setVar', blockType: Scratch.BlockType.COMMAND, text: 'set variable [KEY] to [VALUE]', arguments: { KEY: { type: Scratch.ArgumentType.STRING }, VALUE: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'getVar', blockType: Scratch.BlockType.REPORTER, text: 'get variable [KEY]', arguments: { KEY: { type: Scratch.ArgumentType.STRING } } },

// LISTS

{ opcode: 'createList', blockType: Scratch.BlockType.COMMAND, text: 'create list [LIST]', arguments: { LIST: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'addToList', blockType: Scratch.BlockType.COMMAND, text: 'add [ITEM] to list [LIST]', arguments: { ITEM: { type: Scratch.ArgumentType.STRING }, LIST: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'setItem', blockType: Scratch.BlockType.COMMAND, text: 'set item [INDEX] of list [LIST] to [ITEM]', arguments: { INDEX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 }, LIST: { type: Scratch.ArgumentType.STRING }, ITEM: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'deleteItem', blockType: Scratch.BlockType.COMMAND, text: 'delete item [INDEX] of list [LIST]', arguments: { INDEX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 }, LIST: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'getItem', blockType: Scratch.BlockType.REPORTER, text: 'item [INDEX] of list [LIST]', arguments: { INDEX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 1 }, LIST: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'listLength', blockType: Scratch.BlockType.REPORTER, text: 'length of list [LIST]', arguments: { LIST: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'clearList', blockType: Scratch.BlockType.COMMAND, text: 'clear list [LIST]', arguments: { LIST: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'listContains', blockType: Scratch.BlockType.BOOLEAN, text: 'does list [LIST] contain [ITEM]', arguments: { LIST: { type: Scratch.ArgumentType.STRING }, ITEM: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'listAsArray', blockType: Scratch.BlockType.REPORTER, text: 'list [LIST] as array', arguments: { LIST: { type: Scratch.ArgumentType.STRING } } },

// CHAT-FRIENDLY BLOCKS

{ opcode: 'sendMessage', blockType: Scratch.BlockType.COMMAND, text: 'send message [TEXT] as [USERNAME] in chat [CHAT]', arguments: { TEXT: { type: Scratch.ArgumentType.STRING }, USERNAME: { type: Scratch.ArgumentType.STRING }, CHAT: { type: Scratch.ArgumentType.STRING, defaultValue: 'general' } } },

{ opcode: 'lastMessage', blockType: Scratch.BlockType.REPORTER, text: 'last message in chat [CHAT]', arguments: { CHAT: { type: Scratch.ArgumentType.STRING, defaultValue: 'general' } } },

{ opcode: 'allMessages', blockType: Scratch.BlockType.REPORTER, text: 'all messages in chat [CHAT]', arguments: { CHAT: { type: Scratch.ArgumentType.STRING, defaultValue: 'general' } } },

{ opcode: 'clearChat', blockType: Scratch.BlockType.COMMAND, text: 'clear chat [CHAT]', arguments: { CHAT: { type: Scratch.ArgumentType.STRING, defaultValue: 'general' } } },

{ opcode: 'messageCount', blockType: Scratch.BlockType.REPORTER, text: 'messages count in chat [CHAT]', arguments: { CHAT: { type: Scratch.ArgumentType.STRING, defaultValue: 'general' } } },

// BAN / UNBAN / BANNED WORDS

{ opcode: 'banUser', blockType: Scratch.BlockType.COMMAND, text: 'ban user [USERNAME]', arguments: { USERNAME: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'unbanUser', blockType: Scratch.BlockType.COMMAND, text: 'unban user [USERNAME]', arguments: { USERNAME: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'getBannedWords', blockType: Scratch.BlockType.REPORTER, text: 'get banned words list' },

{ opcode: 'setBannedWords', blockType: Scratch.BlockType.COMMAND, text: 'set banned words list to [LIST]', arguments: { LIST: { type: Scratch.ArgumentType.STRING } } },

// LOGGING

{ opcode: 'clearLogs', blockType: Scratch.BlockType.COMMAND, text: 'clear logs' },

{ opcode: 'logsAsArray', blockType: Scratch.BlockType.REPORTER, text: 'logs as array' },

// CLOUD

{ opcode: 'startHost', blockType: Scratch.BlockType.COMMAND, text: 'start cloud host' },

{ opcode: 'connectCloud', blockType: Scratch.BlockType.COMMAND, text: 'connect to cloud with code [CODE]', arguments: { CODE: { type: Scratch.ArgumentType.STRING } } },

{ opcode: 'cloudStatus', blockType: Scratch.BlockType.REPORTER, text: 'cloud status' }

]

};

}

// ---------- HELPERS ----------

_log(action, user=''){ const log = JSON.parse(localStorage.getItem(this.LOG_KEY)||'[]'); log.push({time:new Date().toISOString(),user,action}); localStorage.setItem(this.LOG_KEY,JSON.stringify(log)); }

_send(type,payload){ if(this.conn && this.conn.open) this.conn.send({type,payload}); }

_syncAll(){ const vars={}, lists={}; for(let k in localStorage){ if(k.startsWith(this.VAR_PREFIX)) vars[k]=localStorage.getItem(k); if(k.startsWith(this.LIST_PREFIX)) lists[k]=localStorage.getItem(k); } this._send('sync',{vars,lists}); }

// ---------- VARIABLES ----------

setVar(a){ localStorage.setItem(this.VAR_PREFIX+a.KEY,a.VALUE); this._log(`set variable ${a.KEY}=${a.VALUE}`); this._send('var',a); }

getVar(a){ return localStorage.getItem(this.VAR_PREFIX+a.KEY)||''; }

// ---------- LISTS ----------

createList(a){ localStorage.setItem(this.LIST_PREFIX+a.LIST,'[]'); this._log(`created list ${a.LIST}`); this._send('list',{name:a.LIST,value:[]}); }

_getList(name){ return JSON.parse(localStorage.getItem(this.LIST_PREFIX+name)||'[]'); }

_setList(name,arr){ localStorage.setItem(this.LIST_PREFIX+name,JSON.stringify(arr)); this._log(`set list ${name}=${JSON.stringify(arr)}`); this._send('list',{name,value:arr}); }

addToList(a){ const l=this._getList(a.LIST); l.push(a.ITEM); this._setList(a.LIST,l); }

setItem(a){ const l=this._getList(a.LIST); if(a.INDEX>0 && a.INDEX<=l.length){ l[a.INDEX-1]=a.ITEM; this._setList(a.LIST,l); } }

deleteItem(a){ const l=this._getList(a.LIST); if(a.INDEX>0 && a.INDEX<=l.length){ l.splice(a.INDEX-1,1); this._setList(a.LIST,l); } }

getItem(a){ return this._getList(a.LIST)[a.INDEX-1]||''; }

listLength(a){ return this._getList(a.LIST).length; }

clearList(a){ this._setList(a.LIST,[]); }

listContains(a){ return this._getList(a.LIST).includes(a.ITEM); }

listAsArray(a){ return JSON.stringify(this._getList(a.LIST)); }

// ---------- CHAT & BANNED WORDS ----------

_chatListName(chat){ return `chat_${chat||'general'}`; }

sendMessage(a){

const user = a.USERNAME||'guest';

const chat = a.CHAT||'general';

const now = Date.now();

if(this.lastMessageTime[user] && now-this.lastMessageTime[user]<this.messageCooldown) return;

this.lastMessageTime[user]=now;

// Check banned users

const banned = JSON.parse(localStorage.getItem(this.BANNED_USERS_KEY)||'[]');

if(banned.includes(user)) return;

// Check banned words

const bannedWords = JSON.parse(localStorage.getItem(this.BANNED_WORDS_KEY)||'[]');

let messageText = a.TEXT.toString().toLowerCase();

let warningCount = JSON.parse(localStorage.getItem(this.WARNINGS_KEY)||'{}');

for(const word of bannedWords){

if(messageText.includes(word.toString().toLowerCase())){

warningCount[user] = (warningCount[user]||0)+1;

localStorage.setItem(this.WARNINGS_KEY, JSON.stringify(warningCount));

this._log(`warning ${warningCount[user]} for user ${user} (word: ${word})`, user);

if(warningCount[user]>=3){

banned.push(user);

localStorage.setItem(this.BANNED_USERS_KEY, JSON.stringify(banned));

this._log(`auto banned user ${user} for repeated banned words`, user);

}

return; // do not send message containing banned word

}

}

const chatList=this._getList(this._chatListName(chat));

chatList.push(`${user}: ${a.TEXT}`);

this._setList(this._chatListName(chat), chatList);

this._log(`send message as ${user}: ${a.TEXT} in chat ${chat}`,user);

}

lastMessage(a){ return this._getList(this._chatListName(a.CHAT))[this._getList(this._chatListName(a.CHAT)).length-1]||''; }

allMessages(a){ return this._getList(this._chatListName(a.CHAT)); }

clearChat(a){ this._setList(this._chatListName(a.CHAT),[]); this._log(`cleared chat ${a.CHAT}`); }

messageCount(a){ return this._getList(this._chatListName(a.CHAT)).length; }

// ---------- BAN / UNBAN ----------

banUser(a){ if(this.getVar({KEY:'username'})!==this.ALLOWED_USER)return; const banned=JSON.parse(localStorage.getItem(this.BANNED_USERS_KEY)||'[]'); if(!banned.includes(a.USERNAME))banned.push(a.USERNAME); localStorage.setItem(this.BANNED_USERS_KEY,JSON.stringify(banned)); this._log(`banned user ${a.USERNAME}`,this.ALLOWED_USER); }

unbanUser(a){ if(this.getVar({KEY:'username'})!==this.ALLOWED_USER)return; let banned=JSON.parse(localStorage.getItem(this.BANNED_USERS_KEY)||'[]'); banned=banned.filter(u=>u!==a.USERNAME); localStorage.setItem(this.BANNED_USERS_KEY,JSON.stringify(banned)); this._log(`unbanned user ${a.USERNAME}`,this.ALLOWED_USER); }

getBannedWords(){ return JSON.stringify(JSON.parse(localStorage.getItem(this.BANNED_WORDS_KEY)||'[]')); }

setBannedWords(a){ localStorage.setItem(this.BANNED_WORDS_KEY,JSON.stringify(a.LIST.split(','))); }

// ---------- LOGS ----------

clearLogs(){ localStorage.setItem(this.LOG_KEY,'[]'); }

logsAsArray(){ return JSON.stringify(JSON.parse(localStorage.getItem(this.LOG_KEY)||'[]')); }

// ---------- CLOUD ----------

startHost(){ if(typeof Peer==='undefined'){alert('PeerJS not loaded yet. Wait a second.'); return;} this.isHost=true; this.peer=new Peer(); this.peer.on('open',id=>{alert('Cloud code: '+id);console.log('Hosting cloud with code:',id);}); this.peer.on('connection',conn=>{this.conn=conn;conn.on('open',()=>this._syncAll());conn.on('data',d=>this._handleData(d));}); }

connectCloud(a){ if(typeof Peer==='undefined'){alert('PeerJS not loaded yet. Wait a second.'); return;} this.peer=new Peer(); this.peer.on('open',()=>{this.conn=this.peer.connect(a.CODE);this.conn.on('data',d=>this._handleData(d));}); }

_handleData(d){ if(d.type==='sync'){Object.entries(d.payload.vars).forEach(([k,v])=>localStorage.setItem(k,v)); Object.entries(d.payload.lists).forEach(([k,v])=>localStorage.setItem(k,v));} if(d.type==='var') localStorage.setItem(this.VAR_PREFIX+d.payload.KEY,d.payload.VALUE); if(d.type==='list') localStorage.setItem(this.LIST_PREFIX+d.payload.name,JSON.stringify(d.payload.value)); }

cloudStatus(){ if(!this.peer)return'offline'; if(this.isHost)return'hosting'; if(this.conn&&this.conn.open)return'connected'; return'connecting'; }

}

Scratch.extensions.register(new LocalStoragePseudoCloud());



0 comments

Loading...

Next up

HOW DO I APEAR THIS HIGH IN THE SEARCH FOR "RALSEI"

thats crazy

curius if it still passes

I WAS SOO DAMN CLOSE

RDLY IS A POKEMON NOW LOL

this is neat

i made this extention btw

its bassically cloud varibles and lists

fucking hell

id 255 hehehe

lez see

oh this one understood negative language

also jeez thats realistic

WHY DIDNT I KNOW THIS EXISTED UNTILL NOW