@infernus/map-loader
Version:
A tool for obj conversion, parsing, and loading
9 lines (8 loc) • 11.6 kB
JavaScript
;var l=require("@infernus/core"),q=require("node:module"),b=require("node:assert"),w=require("node:fs"),U=require("node:path"),Y=require("node:readline"),B=typeof document<"u"?document.currentScript:null;const p={removedBuilding:[],loadedMaps:new Map},X=-1,v="putafuckingspacehere",Z="_",$="~N~",J={OBJECT_MATERIAL_SIZE_32x32:l.ObjectMaterialTextSizeEnum._32x32,OBJECT_MATERIAL_SIZE_64x32:l.ObjectMaterialTextSizeEnum._64x32,OBJECT_MATERIAL_SIZE_64x64:l.ObjectMaterialTextSizeEnum._64x64,OBJECT_MATERIAL_SIZE_128x32:l.ObjectMaterialTextSizeEnum._128x32,OBJECT_MATERIAL_SIZE_128x64:l.ObjectMaterialTextSizeEnum._128x64,OBJECT_MATERIAL_SIZE_128x128:l.ObjectMaterialTextSizeEnum._128x128,OBJECT_MATERIAL_SIZE_256x32:l.ObjectMaterialTextSizeEnum._256x32,OBJECT_MATERIAL_SIZE_256x64:l.ObjectMaterialTextSizeEnum._256x64,OBJECT_MATERIAL_SIZE_256x128:l.ObjectMaterialTextSizeEnum._256x128,OBJECT_MATERIAL_SIZE_256x256:l.ObjectMaterialTextSizeEnum._256x256,OBJECT_MATERIAL_SIZE_512x64:l.ObjectMaterialTextSizeEnum._512x64,OBJECT_MATERIAL_SIZE_512x128:l.ObjectMaterialTextSizeEnum._512x128,OBJECT_MATERIAL_SIZE_512x256:l.ObjectMaterialTextSizeEnum._512x256,OBJECT_MATERIAL_SIZE_512x512:l.ObjectMaterialTextSizeEnum._512x512,OBJECT_MATERIAL_TEXT_ALIGN_LEFT:l.ObjectMaterialAlignmentEnum.LEFT,OBJECT_MATERIAL_TEXT_ALIGN_CENTER:l.ObjectMaterialAlignmentEnum.CENTER,OBJECT_MATERIAL_TEXT_ALIGN_RIGHT:l.ObjectMaterialAlignmentEnum.RIGHT};class g extends Error{constructor(e){super(`[MapLoader] ${JSON.stringify(e)}`),this.context=e}}function h(t,e,a,i){if(i<a)throw new g({type:t,msg:`Expected ${a} elements, got ${i}`,details:JSON.stringify(e)})}l.PlayerEvent.onConnect(({player:t,next:e})=>(p.removedBuilding.flat().forEach(a=>{t.removeBuilding(...a)}),e()));function W(t){return h("removeBuilding",t,6,t.length),t.slice(1).map(e=>{const a=+e;return b(!Number.isNaN(a)),a})}function K(t,e){h("objParser",t,8,t.length);const a=t.map(R=>{const F=Number(R);if(Number.isNaN(F))throw new g({msg:`invalid value ${R}`});return F}),[i,c,o,s,d,n,m,x,u,f,r,_,I,C]=a,{xOffset:O=0,yOffset:y=0,zOffset:D=0,playerId:P,worldId:E,interiorId:M,areaId:j,priority:S,streamDistance:T,drawDistance:A,overwrite:N}=e;return new l.DynamicObject({modelId:i,x:c+O,y:o+y,z:s+D,rx:d,ry:n,rz:m,worldId:N?E:x??E,areaId:N?j:I??j,interiorId:N?M:u??M,streamDistance:N?T:r??T,drawDistance:N?A:_??A,playerId:P,priority:N?S:C??S}).create()}function Q(t,e,a){h("materialTextParser",e,10,e.length);let[i,c,o,s,d,n,m,x]=e.slice(1);b(!Number.isNaN(+i)),b(!Number.isNaN(+c)),b(!Number.isNaN(+d)),b(!Number.isNaN(+n)),b(!Number.isNaN(+x)),o=o.replaceAll(Z," ");const u=e.slice(9).join(" ").replaceAll($,`
`).replaceAll(v," ");return t.setMaterialText(a.charset,+i,u,+c,o,+s,+d,+n,+m,+x)}function ee(t,e){h("materialParser",e,6,e.length);let[a,i,c,o,s]=e.slice(1);return b(!Number.isNaN(+a)),b(!Number.isNaN(+i)),b(!Number.isNaN(+s)),o.includes(v)&&(o=o.replaceAll(v," ")),t.setMaterial(+a,+i,c,o,+s)}function k(t){const e=w.createReadStream(t);return Y.createInterface({input:e,crlfDelay:1/0})}function te(){let t=-1;for(;t===-1;){const e=Math.floor(Math.random()*16777215);p.loadedMaps.has(e)||(t=e)}return t}function V(t,e,a){return t==="16644"&&e==="a51_detailstuff"&&a==="roucghstonebrtb"?{modelId:18888,textureLib:"forcefields",textureName:"white"}:{modelId:+t,textureLib:e,textureName:a}}function L(t,e=2){return"0x"+(t>>>0).toString(16).padStart(e,"0")}function z(t){return t.split(/,(?=(?:[^"]*"[^"]*")*[^"]*$)/).map(e=>e.trim().replace(/^"|"$/g,""))}function re(t,e){const a=U.resolve(t),i=U.resolve(e);return process.platform==="win32"?a.toLowerCase()===i.toLowerCase():a===i}async function ne(t){let e=0,a=null;const i=[],c=[];function o(d){if(!d.length)return;e++;const n=d.split(" "),m=n[0];if(m==="rmv")i.push(W(n));else if(m==="mat"){if(!a)throw new g({msg:"parseLine: no object target, cannot material"});ee(a,n)}else if(m==="txt"){if(!a)throw new g({msg:"parseLine: no object target, cannot materialText"});Q(a,n,t)}else a=K(n,t),c.push(a)}let s=null;try{const{source:d}=t;if(typeof d=="string"){s=k(d);for await(const m of s)o(m.trim())}else{let m=!1;for(;!m;){const x=await d(()=>{m=!0});if(!x.length){m=!0;break}for(const u of x)o(u.trim())}}let n=-1;return i.length&&(n=p.removedBuilding.push(i)-1),l.Player.getInstances().forEach(m=>{if(i.forEach(x=>{m.removeBuilding(...x)}),samp.defined&&samp.defined._colandreas_included)try{const x=(typeof global.require<"u"?global.require:q.createRequire(typeof document>"u"?require("url").pathToFileURL(__filename).href:B&&B.tagName.toUpperCase()==="SCRIPT"&&B.src||new URL("bundle.js",document.baseURI).href))("@infernus/colandreas");i.forEach(u=>{x.removeBuilding(...u)})}catch{}}),{objects:c,removedBuilding:i,removedBuildingIdx:n}}catch(d){throw c.forEach(n=>{n.isValid()&&n.destroy()}),c.length=0,i.length=0,d instanceof g?(d.context.msg=`lineNo: ${e} ${d.context.msg}`,new g(d.context)):d}finally{s&&s.close()}}function ae(t,e){let a="CreateObject";t[2]?a="CreateDynamicObjectEx":t[1]&&(a="CreateDynamicObject");const i=z(e.replace(/^.*Create(Dynamic)?Object(Ex)?\(|\);\s*\/?\*?\w*.*$/g,""));if(h("objConverter",i,7,i.length),a==="CreateObject"){const[c,o,s,d,n,m,x,u]=i;let f=+u;return(!u||u==="STREAMER_OBJECT_DD")&&(f=l.StreamerDistances.OBJECT_DD),{modelId:+c,x:+o,y:+s,z:+d,rX:+n,rY:+m,rZ:+x,worldId:-1,interiorId:-1,playerId:-1,streamerDistance:l.StreamerDistances.OBJECT_SD,drawDistance:f,areaId:-1,priority:0}}else if(a==="CreateDynamicObject"){const[c,o,s,d,n,m,x,u=-1,f=-1,r=-1,_=l.StreamerDistances.OBJECT_SD,I,C=-1,O=0]=i;let y=+I;(!I||I==="STREAMER_OBJECT_DD")&&(y=l.StreamerDistances.OBJECT_DD);let D=+_;return(!_||_==="STREAMER_OBJECT_SD")&&(D=l.StreamerDistances.OBJECT_DD),{modelId:+c,x:+o,y:+s,z:+d,rX:+n,rY:+m,rZ:+x,worldId:+u,interiorId:+f,playerId:+r,streamerDistance:D,drawDistance:y,areaId:+C,priority:+O}}else{const[c,o,s,d,n,m,x,u,f,r,_,I,C,O=0]=i;let y=+f;(!f||f==="STREAMER_OBJECT_DD")&&(y=l.StreamerDistances.OBJECT_DD);let D=+u;return(!u||u==="STREAMER_OBJECT_SD")&&(D=l.StreamerDistances.OBJECT_DD),{modelId:+c,x:+o,y:+s,z:+d,rX:+n,rY:+m,rZ:+x,worldId:-1,interiorId:-1,playerId:-1,streamerDistance:D,drawDistance:y,areaId:-1,priority:+O}}}function ie(t){const e=z(t.replace(/^.*Set(Dynamic)?ObjectMaterial\(|\);\s*\/?\*?\w*.*$/g,""));h("materialConverter",e,6,e.length);let[a,i,c,o,s,d]=e;const n=V(c,o,s);let m=n.modelId;return o=n.textureLib,s=n.textureName,s.includes(" ")&&(s=s.replaceAll(" ",v)),{index:+i,modelId:m,textureLib:o,textureName:s,color:+d}}function oe(t,e){let a="SetObjectMaterialText";t[1]&&(a="SetDynamicObjectMaterialText");const i=z(e.replace(/^.*Set(Dynamic)?ObjectMaterialText\(|\);\s*\/?\*?\w*.*$/g,""));h("materialTextConverter",i,9,i.length);let[c,o,s,d,n,m,x,u,f,r=l.ObjectMaterialAlignmentEnum.LEFT]=i;a==="SetObjectMaterialText"&&([o,s]=[s,o]),s=s.replace(/\n|\\n/g,$),n=n.replaceAll(" ",Z);let _=+d;d in J&&(_=J[d]);let I=+r;return r in J&&(I=J[r]),{materialIndex:+o,text:s,materialSize:_,fontFace:n,fontSize:+m,bold:+!!x,fontColor:u,backColor:f,textAlignment:I}}function le(t){const e=z(t.replace(/^.*RemoveBuildingForPlayer\(|\);\s*\/?\*?\w*.*$/g,""));h("removeBuildingConverter",e,6,e.length);const[a,i,c,o,s,d]=e;return{modelId:+i,centerX:+c,centerY:+o,centerZ:+s,radius:+d}}async function ce(t){const{input:e,output:a,removeOutput:i}=t;b(!re(e,a));const c=k(e);i!==!1&&w.existsSync(a)&&w.unlinkSync(a);const o=w.createWriteStream(a,{flags:"a"}),s=[/^.*Create(Dynamic)?Object(Ex)?\(/,/^.*Set(Dynamic)?ObjectMaterial\(/,/^.*Set(Dynamic)?ObjectMaterialText\(/,/^.*RemoveBuildingForPlayer\(/];let d=0;try{for await(const n of c){d++;let m=null;const x=s.findIndex(r=>(m=n.match(r),m));if(x===-1)continue;let u=[];if(x===0){const r=ae(m,n);u=[r.modelId,r.x.toFixed(6),r.y.toFixed(6),r.z.toFixed(6),r.rX.toFixed(6),r.rY.toFixed(6),r.rZ.toFixed(6),r.worldId,r.interiorId,r.playerId,r.streamerDistance.toFixed(6),r.drawDistance.toFixed(6),r.areaId,r.priority]}else if(x===1){const r=ie(n);u=["mat",r.index,r.modelId,r.textureLib,r.textureName,L(r.color,8)]}else if(x===2){const r=oe(m,n);u=["txt",r.materialIndex,r.materialSize,r.fontFace,r.fontSize,+r.bold,L(+r.fontColor),L(+r.backColor,8),r.textAlignment,r.text]}else if(x===3){const r=le(n);u=["rmv",r.modelId,r.centerX.toFixed(6),r.centerY.toFixed(6),r.centerZ.toFixed(6),r.radius.toFixed(2)]}if(u.some(r=>Number.isNaN(r)||r==="NaN"))throw new g({msg:"Invalid Value Converted: NaN",details:n});const f=u.join(" ")+`
`;o.write(f)||await new Promise(r=>o.once("drain",r))}}catch(n){throw n instanceof g?(n.context.msg=`lineNo: ${d} ${n.context.msg}`,new g(n.context)):n}finally{await new Promise((n,m)=>{o.once("error",m),o.once("finish",n),o.once("close",n),o.end()})}}async function se(t){const{output:e,removeOutput:a}=t;a!==!1&&w.existsSync(e)&&w.unlinkSync(e);const i=w.createWriteStream(e,{flags:"a"});try{const c=l.Streamer.getUpperBound(l.StreamerItemTypes.OBJECT);for(let o=1;o<=c;o++){if(!l.DynamicObject.isValid(o))continue;const s=l.Streamer.getIntData(l.StreamerItemTypes.OBJECT,o,l.E_STREAMER.MODEL_ID),d=l.Streamer.getIntData(l.StreamerItemTypes.OBJECT,o,l.E_STREAMER.WORLD_ID),n=new l.DynamicObject(o),{x:m,y:x,z:u}=n.getPos(),{rx:f,ry:r,rz:_}=n.getRot(),I=[s,m.toFixed(6),x.toFixed(6),u.toFixed(6),f.toFixed(6),r.toFixed(6),_.toFixed(6),d].join(" ")+`
`,C=[],O=[];for(let E=0;E<15;E++)if(n.isMaterialUsed(E)){let{modelId:M,materialColor:j,txdName:S,textureName:T}=n.getMaterial(E);const A=V(M,S,T);M=A.modelId,S=A.textureLib,T=A.textureName,T.includes(" ")&&(T=T.replaceAll(" ",v)),C.push(["mat",E,M,S,T,L(j,8)].join(" "))}for(let E=0;E<15;E++)if(n.isMaterialTextUsed(E)){let{text:M,materialSize:j,fontFace:S,fontSize:T,bold:A,fontColor:N,backColor:R,textAlignment:F}=n.getMaterialText(E);M=M.replace(/\n|\\n/g,$),S=S.replaceAll(" ",Z),O.push(["txt",E,j,S,T,A,L(N),L(R,8),F,M].join(" "))}const y=C.join(`
`),D=O.join(`
`),P=I+y+(C.length?`
`:"")+D+(O.length?`
`:"");i.write(P)||await new Promise(E=>i.once("drain",E))}}finally{await new Promise((c,o)=>{i.once("error",o),i.once("finish",c),i.once("close",c),i.end()})}}l.GameMode.onExit(({next:t})=>(p.loadedMaps.clear(),t()));async function G(t){const{objects:e,removedBuilding:a,removedBuildingIdx:i}=await ne(t),c=te();p.loadedMaps.set(c,{options:t,objects:e,_rmvBuildingIdx:i});const{onLoaded:o}=t;return o&&o(e,a),c}function de(t){if(!p.loadedMaps.has(t))throw new g({msg:`invalid mapId ${t}`});const e=p.loadedMaps.get(t),{onUnloaded:a}=e.options;e.objects.forEach(c=>{c.isValid()&&c.destroy()});const i=e._rmvBuildingIdx>-1?p.removedBuilding[e._rmvBuildingIdx]:[];if(e._rmvBuildingIdx>-1&&p.removedBuilding.splice(e._rmvBuildingIdx,1),p.loadedMaps.delete(t),samp.defined&&samp.defined._colandreas_included)try{const c=(typeof global.require<"u"?global.require:q.createRequire(typeof document>"u"?require("url").pathToFileURL(__filename).href:B&&B.tagName.toUpperCase()==="SCRIPT"&&B.src||new URL("bundle.js",document.baseURI).href))("@infernus/colandreas");i.forEach(o=>{c.restoreBuilding(...o)})}catch{}return a&&a(i),t}function H(t){const e=p.loadedMaps.get(t);if(!e)throw new g({msg:`invalid mapId ${t}`});G(e.options)}function me(){p.loadedMaps.keys().forEach(t=>{H(t)})}function ue(){return p.loadedMaps.size}function xe(t){const e=p.loadedMaps.entries().find(([,a])=>a.objects.find(i=>i===t));return e?e[0]:X}function Ee(t){return p.loadedMaps.get(t)}exports.INVALID_MAP_ID=X,exports.getMapCount=ue,exports.getMapIDFromObject=xe,exports.getMapInfoFromID=Ee,exports.loadMap=G,exports.mapConverter=ce,exports.mapExporter=se,exports.reloadMap=H,exports.reloadMaps=me,exports.unloadMap=de;